SimHub plugin + custom Dash Studio dashboard that pipes live Formula 1 telemetry from F1's broadcast feed (or MultiViewer replay) onto a SimHub-connected wheel screen.
The current F1RaceSim_GSIFPEV2 dashboard is laid out for an 800×480 wheel screen and has been validated on the GSI Formula Pro Elite V2 and GSI Hyper P1. Any other SimHub-LCD-capable wheel at the same resolution should also work; resolutions other than 800×480 will crop or scale.
You pick a driver number (44 = Hamilton, 1 = Verstappen, 16 = Leclerc, …). The plugin pulls that driver's RPM, gear, speed, throttle, brake, DRS, lap time, sector splits, gap to leader, tyre compound, pit stops, weather, track status and race-control flags. The companion F1RaceSim_GSIFPEV2 dashboard renders all of it as a broadcast-style dash with shift lights driven by the live RPM.
This is a fan tool for use during F1 broadcasts on F1 TV / official live timing.
F1 TV broadcast (~1–3s behind live)
│
▼
[ livetiming.formula1.com SignalR ] [ F1 MultiViewer local HTTP ]
│ │
└──────────────┬───────────────────────────────┘
▼
F1SimHubLive plugin (this repo)
│ (60 Hz interpolated render of ~3–10 Hz feed)
▼
SimHub property tree
│
▼
F1RaceSim_GSIFPEV2 Dash Studio dashboard
│
▼
Your SimHub-connected wheel screen + LEDs
- Quick install (installer)
- Fresh-machine setup (first-time GSI wheel)
- What it does
- Architecture
- Two data sources: F1 Live vs MultiViewer
- SimHub property reference
- F1RaceSim_GSIFPEV2 dashboard
- Driver Picker (mid-race driver switching)
- Build the plugin
- Install (manual)
- Configure
- Run a session
- Troubleshooting
- File layout
- Known limitations
- License
- Companion docs
- Contributing
The easiest way to deploy F1SimHubLive to a new machine (for example, your media-room PC where you watch F1 TV via MultiViewer):
- Download the latest
F1SimHubLive-Installer.exefrom the Releases page. - Prerequisites on the target machine (install in this exact order if the wheel has never been connected to this PC before — see Fresh-machine setup below):
- SimHub installed.
- F1 MultiViewer installed and signed in with an active F1 TV subscription.
- A Live Timing session running inside MultiViewer — for a replay, after loading the session you must click "Replay Live Timing" so the local API at
http://localhost:10101actually emits telemetry. Watching only the video feed is not enough; the prereq probe and the plugin both pull from the Live Timing data stream, which is only active in that view. - GSI SimOS installed (the wheel's vendor companion — install BEFORE plugging in the wheel for the first time).
- Your GSI wheel connected via USB and visible in SimHub Devices.
- Right-click the .exe → Run as administrator (it needs to write under
Program Files (x86)\SimHub\). - Walk through the four-step wizard:
- Welcome — overview.
- Prerequisites — auto-detects SimHub + F1 MultiViewer install paths, probes the MultiViewer API to confirm your F1 TV subscription is active and that Live Timing is actively streaming (a successful
SessionInforesponse — not justHeartbeat). - Driver & source — pick any driver from the dropdown (loaded live from MultiViewer's current grid, with a bundled fallback list). Choose data source (MultiViewer recommended — works for both live and replays).
- Install — copies the plugin DLLs, dashboard files, writes
F1SimHubLive.Settings.json, rewires any legacy plugin-name references in per-device LED configurations (see LED config auto-rewire below), and restarts SimHub.
- After install, in SimHub: enable the plugin under Settings → Plugins, then open Dash Studio → F1RaceSim_GSIFPEV2 and select it on your wheel.
The installer is a single self-contained .exe (~90 MB) — no .NET runtime install required on the target machine. Source for the installer lives under installer/.
On launch, the installer asks the GitHub Releases API whether a newer version exists. If yes, a yellow banner appears at the top of the Welcome page with a Download button (opens the latest release in your browser) and a Continue button (proceed with what you have). The check runs once per launch, has a 3-second timeout, and never blocks install — if you're offline, GitHub is rate-limiting, or anything else goes wrong, the banner simply stays hidden and the installer behaves exactly as before. This means an installer .exe sitting in your Downloads folder for months won't silently put you out of date — it will tell you when you run it.
The installer also reads FileVersionInfo of any existing F1SimHubLive.dll already deployed under your SimHub directory and logs both the existing and freshly-installed versions to the deploy log pane, so upgrades are explicit (e.g. "Existing F1SimHubLive.dll detected — version 1.1.0. … Installed F1SimHubLive.dll version 1.1.1.") rather than silent overwrites.
This plugin was renamed twice during early development (F1SimSubGSIPlugin → F1SimHubGSIPlugin → F1SimHubLivePlugin). Plugin-name string references live in two places SimHub uses:
- Dashboard files (
*.djson) — these have always been kept in sync with each rename. - Per-device LED configurations (
PluginsData\Common\Devices\<guid>\settings.json) — these were NOT touched by earlier installers. If you ran a pre-v1.0.3 install (or hand-authored your LED zones against an early build of the plugin), every zone-enable formula likeif([F1SimSubGSIPlugin.RpmPercent] > 78, 1, 0)silently evaluates to 0 once the old plugin DLL is uninstalled — and your wheel LEDs blink white only with no RPM gradient.
From v1.0.3 onward, the installer scans every SimHub device's settings.json, replaces any F1SimSubGSIPlugin. and F1SimHubGSIPlugin. prefixes with F1SimHubLivePlugin., and writes a timestamped settings.json.preLedRewire-<YYYYMMDD-HHMMSS> backup before mutating each touched file. The pass is idempotent — re-running the installer on an already-clean device is a no-op and creates no extra backups.
You'll see lines like this in the deploy log pane:
Scanning per-device LED configurations for stale plugin-name references...
Device 'GSI Formula Pro Elite V2': backed up settings.json -> settings.json.preLedRewire-20260525-204334
Device 'GSI Formula Pro Elite V2': rewired 10 legacy plugin reference(s) -> F1SimHubLivePlugin.*.
LED config rewire: patched 10 reference(s) across 1 device(s).
If the target PC has never had a GSI Formula Pro Elite V2 wheel connected, follow this exact order. Doing it out of order is the single most common cause of "wheel shows up but LCD/LEDs don't work" headaches.
When Windows sees a new USB HID device, it auto-binds a generic HID driver. That driver is enough to expose buttons and axes to games, but it does not expose the wheel's LCD, RGB LEDs, or programmable features. The vendor companion (GSI SimOS) installs the device profile that unlocks those — but only if it's installed before the wheel is first enumerated. If you plug in first and install second, you may end up with a partially-bound device that needs to be unplugged + replugged before the full feature set comes online.
- Install SimHub — https://www.simhubdash.com/. Default install path (
C:\Program Files (x86)\SimHub\). Run it once so the first-launch wizard completes. - Install F1 MultiViewer — https://multiviewer.app/. Sign in with your F1 TV Pro account. Start a session (live or replay) and open Live Timing — for replays, click the "Replay Live Timing" button on the session card. Confirm
http://localhost:10101/api/v1/live-timing/SessionInforeturns populated JSON in your browser. (MultiViewer is only needed if you'll use theMultiViewerdata source. TheF1Livesource talks to F1's broadcast SignalR feed directly and does not need MultiViewer. Note: just watching the F1 video stream inside MultiViewer is not enough — telemetry only flows once Live Timing is running.) - Install GSI SimOS — get the latest installer from the wheel's product page at https://gomezsimindustries.com/products/formula-pro-elite-v2. Do this with the wheel UNPLUGGED. Reboot if the installer asks you to.
- Plug the wheel into USB (wheel powered off → plug → power on, or follow the order in your wheel's quick-start card). Windows will run final HID enumeration; SimOS should pop up or sit in the tray and recognize the wheel.
- Open SimOS and verify the wheel is detected. If it prompts for a firmware update, run it now — do not unplug the wheel mid-update. Wait for the "complete" confirmation before doing anything else.
- Open SimHub → Settings → Devices → confirm the wheel appears (typically as a GSI device on a HID path). Add it as a controllable device if SimHub doesn't auto-add it.
- Run
F1SimHubLive-Installer.exe(this repo's installer) as administrator. The wizard auto-detects SimHub + MultiViewer, lets you pick a driver, deploys the plugin DLLs + dashboard, and restarts SimHub. - In SimHub → Settings → Plugins → enable F1SimHubLive. Then Dash Studio → F1RaceSim_GSIFPEV2 → assign it to the GSI device.
Not catastrophic. Do this:
- Close SimHub.
- Unplug the wheel from USB and power it off.
- Install GSI SimOS.
- Reboot.
- Plug the wheel back in, power it on, let SimOS finish enumeration.
- Continue from step 5 above.
In Device Manager, the wheel should appear under Human Interface Devices with no yellow warning triangle. In SimHub Devices, button presses should register a green ring around the input list. If both of those are clean, the plugin + dashboard install on top will work.
Live telemetry (60 Hz interpolated):
- RPM, RpmPercent (0–100 normalized over 13,000)
- Gear (0–8)
- Speed (km/h)
- Throttle / Brake (0–100)
- DRS (raw code +
DrsActive/DrsEligiblebool)
Per-driver timing (1 Hz race-control refresh):
- Position (1st–20th)
- Lap, CurrentLap / TotalLaps,
LapDisplay(e.g.47/53) - BestLapTime, LastLapTime
- GapToLeader, IntervalToAhead
- InPit, PitStopCount
- TyreCompound + short letter (
S/M/H/I/W), TyreAge - Sector 1/2/3 times + personal-best + overall-best flags
- Ahead driver's sectors + AheadCarNumber
- Leader's sectors + LeaderCarNumber
- TopSpeed in km/h + TopSpeedRank
- OvertakeSystemEnabled / OvertakeAvailable
Session state:
- SessionTimeRemaining (
HH:MM:SS) - TrackStatus (text) and TrackStatusCode (1=AllClear, 2=Yellow, 3=GreenAll, 4=SC, 5=Red, 6=VSC, 7=VSC_Ending)
- FlagText — last race-control flag broadcast (GREEN, YELLOW, DOUBLE YELLOW, SC, VSC, RED, CHEQUERED)
- TotalDrivers
Weather:
- AirTemp °C, TrackTemp °C, Humidity %, Rainfall bool, WindSpeedKph
┌─────────────────────────────────────────────────────────────────┐
│ Data source (one of) │
│ • F1SignalRClient → wss://livetiming.formula1.com (broadcast) │
│ • MultiViewerHttpClient → http://localhost:10101 (replay) │
└─────────────────────────────────────────────────────────────────┘
│ raw SignalR/JSON
▼
┌─────────────────────────────────────────────────────────────────┐
│ Decoders (per F1 topic) │
│ CarData.z → DriverSnapshot (RPM/Gear/Speed/Throt/etc) │
│ TimingData → TimingSnapshot (Pos/Gap/Sectors/etc) │
│ TimingStats → TopSpeed │
│ TimingAppData → Tyre compound/age, pit stops │
│ WeatherData → WeatherSnapshot │
│ TrackStatus → SessionSnapshot.TrackStatusCode/Message │
│ LapCount → CurrentLap / TotalLaps │
│ RaceControl → FlagText │
│ SessionData → SessionTimeRemaining │
│ DriverList → driver→racing-number map │
│ ExtrapolatedClock → session clock fallback │
└─────────────────────────────────────────────────────────────────┘
│
┌───────────┴──────────────┐
▼ ▼
TelemetryBuffer OnTimingSnapshot/OnSessionSnapshot/
(prev + curr car OnWeatherSnapshot/OnStatus events
snapshot, ring)
│
▼
Interpolator (60 Hz)
│
▼
F1SimHubLivePlugin.DataUpdate / per-event setters
│
▼
SimHub PluginManager.SetPropertyValue(...)
│
▼
F1RaceSim_GSIFPEV2.djson (Dash Studio) → GSI wheel HID screen + LEDs
Why 60 Hz interpolation? The broadcast multiplexes ~20 cars onto a single feed; per-car samples arrive at roughly 3–10 Hz with jitter. The plugin holds a ~200 ms render buffer and linearly interpolates between the last two snapshots so shift lights, throttle bars and RPM gauges look smooth instead of stepping.
Set Source in F1SimHubLive.Settings.json:
| Value | What it connects to | When to use |
|---|---|---|
F1Live (default) |
livetiming.formula1.com SignalR 2.x hub Streaming |
Live sessions only (FP1/2/3, Q, Sprint, Race). Data flows only while F1 is actively broadcasting. |
MultiViewer |
Local F1 MultiViewer app at http://localhost:10101 |
Replays from F1 TV recordings, paused sessions, or testing outside live windows. Requires MultiViewer running with a session loaded and Live Timing actively running — for replays, click "Replay Live Timing" on the session. Watching only the video feed produces no telemetry. |
The F1Live source has zero local dependencies. MultiViewer mode lets you scrub through past races for testing — used heavily during development to validate the dashboard against known SC/VSC/yellow events.
All properties are exposed under the F1SimHubLivePlugin namespace (class name, not [PluginName] attribute). In Dash Studio bindings use $prop('F1SimHubLivePlugin.X') or [F1SimHubLivePlugin.X].
| Property | Type | Range / values |
|---|---|---|
Rpm |
double | 0–~15000 |
RpmPercent |
double | 0–100 (normalized over 13000) |
Gear |
int | 0=N/R, 1–8 |
Speed |
double | km/h |
Throttle |
double | 0–100 |
Brake |
double | 0–100 |
Drs |
int | raw DRS code |
DrsActive |
bool | true if 10/12/14 |
DrsEligible |
bool | true if eligibility flag set |
| Property | Notes |
|---|---|
Position |
string, current finishing position |
Lap |
this driver's lap counter |
BestLapTime / LastLapTime |
formatted M:SS.ddd |
GapToLeader |
+12.345 or +1 LAP |
IntervalToAhead |
gap to car directly ahead |
InPit |
bool |
TyreCompound / TyreCompoundShort |
SOFT / S, etc. |
TyreAge |
int laps |
PitStopCount |
int |
TopSpeed |
string km/h |
TopSpeedRank |
int (1 = fastest in field) |
OvertakeSystemEnabled |
bool |
OvertakeAvailable |
bool |
| Property | Type |
|---|---|
Sector1Time / Sector2Time / Sector3Time |
string |
SectorNIsPersonalBest |
bool (green) |
SectorNIsOverallBest |
bool (purple) |
| Property | Notes |
|---|---|
AheadCarNumber |
F1 racing number of car directly in front |
LeaderCarNumber |
F1 racing number of current leader |
AheadSectorNTime / AheadSectorNIs(Personal/Overall)Best |
mirrors above |
LeaderSectorNTime / LeaderSectorNIs(Personal/Overall)Best |
mirrors above |
| Property | Type |
|---|---|
CurrentLap / TotalLaps |
int |
LapDisplay |
string 47/53 |
SessionTimeRemaining |
string HH:MM:SS |
TrackStatus |
string |
TrackStatusCode |
int (see below) |
FlagText |
string (RC broadcast) |
TotalDrivers |
int |
TrackStatusCode values:
| Code | Meaning |
|---|---|
| 1 | AllClear |
| 2 | Yellow |
| 3 | Green (transitional after yellow) |
| 4 | Safety Car (SC) |
| 5 | Red Flag |
| 6 | VSC Deployed |
| 7 | VSC Ending |
AirTemp (°C), TrackTemp (°C), Humidity (%), Rainfall (bool), WindSpeedKph.
| Property | Notes |
|---|---|
Source |
F1Live or MultiViewer |
CurrentDriverNumber |
driver being tracked |
Status |
connection state (Initializing → Connecting → Connected → …) |
Populated once per session as soon as the upstream DriverList is fetched. Empty strings until then.
| Property | Example | Notes |
|---|---|---|
DriverTla |
VER |
Three-letter code |
DriverFirstName |
Max |
As provided by F1 feed |
DriverLastName |
Verstappen |
Use .toUpperCase() in dashboard for broadcast style |
DriverFullName |
Max VERSTAPPEN |
Feed-provided full name |
DriverBroadcastName |
M VERSTAPPEN |
F1 broadcast convention; synthesized when feed omits it |
TeamName |
Red Bull Racing |
|
TeamColour |
3671C6 |
Team accent hex (no leading #) |
F1RaceSim_GSIFPEV2 is a custom Dash Studio template that ships in dashboards/F1RaceSim_GSIFPEV2.djson. It mimics the F1 TV broadcast graphic layout, scaled for the GSI wheel's 800×480 screen.
The screen is laid out as a 3-column broadcast grid: left = timing column, center = telemetry column, right = pace column, plus a top status strip and a bottom data strip.
┌────────────────────────────────────────────────────────────────────┐
│ ☀ 19/33 HAMILTON 🕐 16:14 ⏳ 1:31:19 │ TOP STRIP
│ AirT/TrkT (driver name, session session time │
│ °C in team color) clock remaining │
├────────────────────────────────────────────────────────────────────┤
│ [12 INT] ┌────────┐ │
│ +2.757 │ 303 │ LAP 19/53 POS 4/22│
│ 34.399 41.758 17.938 │ SPEED │ │
│ S1 S2 S3 │ │ INPUTS │
│ │ 🚗 │ BRAKE PRESSURE │
│ 34.919 41.921 18.119 │ │ ━━━━━━━━━━━━━━━ │
│ ← own driver, color-coded │ 8 │ THROTTLE POSITION │
│ (purple=overall, green=PB, │ GEAR │ ━━━━━━━━━━━━━━━ │
│ yellow=other) │ │ │
│ │ 10580 │ @vicslive │
│ 34.720 42.014 18.054 │ RPM │ github · instagram│
│ ← leader's reference sectors └────────┘ │
│ +5.985 │
│ [63 LDR] LAST 1:34.959 │
│ GAP +5.985 │
├────────────────────────────────────────────────────────────────────┤
│ TYRE M 17L STOPS 0 TOP 324 OVT WAIT CLEAR │ BOTTOM STRIP
│ compound/age stops top speed overtake mode flag/track state│
└────────────────────────────────────────────────────────────────────┘
Top strip — at-a-glance session context: live weather (air / track temp with a sun or rain icon), the selected driver's last name in the live team colour, the wall-clock time, and the session time remaining.
Center telemetry column — the big numbers you actually drive by: live SPEED (km/h, cyan box), the selected driver's current GEAR (huge white digit, dominates the screen), and RPM (yellow box, also reflected in the shift-light LEDs). RPM-driven shift lights wrap the screen edge.
Left timing column — sector splits laid out like the F1 international feed timing tower:
- Top:
INTpill (car directly ahead, with its car number) + the gap to it (+2.757), then that car's last three sector times. - Middle: your driver's three sector times, coloured purple for overall-best, green for personal-best, yellow otherwise.
- Bottom: leader's three sector times + the gap to leader (
+5.985) +LDRpill with leader's car number.
Right pace column — LAP M/N and POSITION X/N pills, the INPUTS panel (BRAKE PRESSURE yellow bar above, THROTTLE POSITION white bar below — same convention as the F1 international feed input overlay), the @vicslive signature widget, and a LAST/GAP readout for the selected driver's most recent lap time and current race gap to leader.
Bottom strip — race-status data row: tyre compound (M/S/H/I/W) plus age in laps, pit-stop count, top speed (running max + speed-trap fused — see the changelog), overtake mode availability, and a flag widget (CLEAR / YELLOW / SC / VSC / RED / CHEQUERED) synced with a red triangle in the top-left for full-course-caution states.
| Widget | Bound to | Notes |
|---|---|---|
| Shift lights (LEDs) | RpmPercent |
12000 RPM ≈ 92% → all green; 13000 RPM = 100% red. |
Speed cyan box |
Speed |
km/h |
Big Gear digit |
Gear |
dominates the center column |
Rpm yellow box |
Rpm |
numeric, matches the LED bar |
Throttle bar (ThrottleChart) |
Throttle |
white, labelled THROTTLE POSITION |
Brake bar (BrakeChart) |
Brake |
yellow, labelled BRAKE PRESSURE |
| DRS indicator | DrsActive / DrsEligible |
|
LAP pill |
LapDisplay |
format M/N (current/total) |
POS pill |
Position + TotalDrivers |
format X/N |
| Driver name title | DriverLastName upper-case → F1 LIVE fallback. TextColor uses TeamColour when Status='Connected'. |
Live broadcast colour (Ferrari #E80020, Mercedes #27F4D2, etc.) |
AheadNumber pill |
AheadCarNumber |
"INT" pill to the LEFT of the ahead sectors row |
BehindNumber pill |
LeaderCarNumber (blank if Position==1) |
"LDR" pill to the LEFT of the leader sectors row |
| Own sector 1/2/3 | SectorNTime + SectorNIs(Personal/Overall)Best |
purple = overall-best, green = personal-best, yellow = other |
| INT sectors row | AheadSectorNTime + ahead best flags |
car directly in front |
| LDR sectors row | LeaderSectorNTime + leader best flags |
race leader |
Gap to ahead (+2.757) |
IntervalToAhead |
shown between INT pill and your driver's sectors |
Gap to leader (+5.985) |
GapToLeader |
shown above the LDR pill |
| LAST / GAP cluster | LastLapTime / GapToLeader |
inside the right pace column |
| Weather (top-left) | AirTemp / TrackTemp / Rainfall |
sun / rain icon driven by Rainfall boolean |
| Session clock (top-right) | SessionClock |
wall-clock time string |
| Session time remaining (top-right) | SessionTimeRemaining |
hourglass icon |
Tyre (TYRE) |
TyreCompoundShort + TyreAge |
bottom strip |
Stops (STOPS) |
PitStopCount |
bottom strip |
Top Speed (TOP) |
TopSpeed + TopSpeedRank |
bottom strip — running max of every live Speed sample fused with the upstream BestSpeeds.ST snapshot, sanity-capped at 450 km/h |
Overtake (OVT) |
OvertakeAvailable |
bottom strip — WAIT / READY / USED |
Top-left triangle (INCLogo + IncCount) |
TrackStatusCode |
Repurposed from iRacing incidents counter. Shows when code ∈ {2,4,5,6,7}. Text: YELLOW / SC / RED / VSC. Color: red for RED flag, amber otherwise. |
Bottom-right F1Flag |
FlagText (priority) → fallback TrackStatusCode |
Synced with top triangle. Green for CLEAR/GREEN, amber for YELLOW/SC/VSC/DOUBLE YELLOW, red for RED, white for CHEQUERED. |
@vicslive signature |
static | Personal handle widget, sits between the INPUTS panel and the LAST/GAP readout in the right column. |
The dashboard uses two flag indicators that stay in sync:
- Top-left triangle (
INCLogored hazard +IncCounttext): driven byTrackStatusCode(persistent track state). Hidden when CLEAR. - Bottom-right
F1Flag: driven byFlagText(race-control broadcast); falls back toTrackStatusCodewhen no active RC message so the two stay aligned during VSC/SC/YELLOW.
Color convention (per F1 broadcast standard):
- 🟢 Green text = CLEAR / GREEN
- 🟡 Amber text + 🔺 red triangle = YELLOW / SC / VSC (race continues, caution active)
- 🔴 Red text + 🔺 red triangle = RED flag (race halted)
- ⚪ White text = CHEQUERED (race finished)
Hamilton crashes on lap 23. You want to flip the wheel to Antonelli without stopping SimHub, editing JSON, and sitting through MultiViewer's ~30-second warm-up after a restart. That's what the F1SimHubLive Driver Picker is for.
┌──────────────────────────────────┐
│ F1SimHubLive — Driver Picker ⌄ │
├──────────────────────────────────┤
│ ┌────┐ Lando NORRIS │
│ │NOR │ McLaren · 374 pts 4 │ ← team-coloured tile + name/team/points + race number
│ └────┘ │
│ ┌────┐ Oscar PIASTRI │
│ │PIA │ McLaren · 356 pts 81 │ ← same team paired, ordered by points
│ └────┘ │
│ ┌────┐ George RUSSELL │
│ │RUS │ Mercedes · 245 pts 63 │
│ └────┘ │
│ ┌────┐ Kimi ANTONELLI │
│ │ANT │ Mercedes · 64 pts 12 │
│ └────┘ │
│ … │
│ ┌────┐ Lewis HAMILTON │ ← currently active driver: coloured border
│ │HAM │ Ferrari · 142 pts 44 │
│ └────┘ │
└──────────────────────────────────┘
Click any driver tile. The row flashes green for 500ms. About one second later your wheel is showing that driver's RPM, gear, speed, lap, gap, sectors — without SimHub or MultiViewer being touched.
- Standalone WPF window, ~320×640, always-on-top by default. Designed to live in the corner of a second monitor during the race.
- Polls MultiViewer's
DriverListevery 5 seconds, so it always shows the current grid. Bundled fallback list when MV is unreachable. - Drivers are grouped by team, and teams are ordered by current
Constructors' Championship position (from MultiViewer's
ChampionshipPrediction). Within a team, the higher-points driver is listed first. Each driver's current points tally is shown subtly under their racing number. - One click on a driver writes the new
DriverNumbertosettings.json. The plugin'sFileSystemWatcherpicks up the change within ~250ms and the wheel flips to the new driver inside about a second — no SimHub restart, no MV warm-up wait. - The currently-active driver row is highlighted with a coloured border. Hover any other driver and the row glows; click and it blinks green for 500ms as the confirm.
- Graceful fallback to race-number order when standings are unavailable (qualifying-only sessions, MV offline, season-opening race).
The v1.1.0 installer creates an All-Users Start Menu shortcut:
Start Menu → F1SimHubLive → F1SimHubLive Driver Picker
You can also pin it to the taskbar. The picker is installed alongside the plugin DLLs in the SimHub install directory:
C:\Program Files (x86)\SimHub\F1SimHubLive-Picker.exe
If you want the picker to launch automatically when SimHub starts, set
AutoLaunchPicker to true in settings.json. Off by default because the
picker needs to write to Program Files (x86)\SimHub\settings.json, which
requires admin — so it ships with a requireAdministrator manifest, and
auto-launching it from SimHub will trigger a UAC prompt every time SimHub
starts. Most people prefer the Start Menu shortcut.
If you've built the repo from source and just want the picker live on your machine without bouncing through the full installer, run from an elevated PowerShell:
cd C:\path\to\F1SimHubLive
.\scripts\install-picker.ps1The script auto-publishes the picker if needed, copies the exe into the
SimHub install dir, and creates the Start Menu shortcut. -NoShortcut to
skip the shortcut, -SimHubPath <dir> for non-default SimHub installs.
Requirements
- Windows
- SimHub 9.x installed at
C:\Program Files (x86)\SimHub - .NET SDK 8.0 (build-time only) —
winget install Microsoft.DotNet.SDK.8 - .NET Framework 4.8 runtime (already present if SimHub runs)
Build
cd $env:USERPROFILE\F1SimHubLive
dotnet restore
dotnet build -c ReleaseOutput location (important — not bin\Release\net48\):
%USERPROFILE%\F1SimHubLive\bin\Release\F1SimHubLive.dll
%USERPROFILE%\F1SimHubLive\bin\Release\Microsoft.AspNet.SignalR.Client.dll
%USERPROFILE%\F1SimHubLive\bin\Release\Newtonsoft.Json.dll
Auto-deploy. After a successful Release build, an AfterBuild target invokes scripts\deploy.ps1 to copy F1SimHubLive.dll into C:\Program Files (x86)\SimHub\ and mirror dashboards\F1RaceSim_GSIFPEV2\ into C:\Program Files (x86)\SimHub\DashTemplates\F1RaceSim_GSIFPEV2\. The deploy skips gracefully if SimHub is running (the DLL would be locked) or if SimHub is not installed — it never fails the build. You still have to restart SimHub to pick up the changes; the script prints a loud reminder when it finishes.
Opt out:
dotnet build -c Release -p:DeploySimHub=falseOne-shot dev iteration (deploy + relaunch SimHub) — assumes SimHub is already closed:
dotnet build -c Release -p:StartSimHub=trueOr run the deploy step on its own after a build:
powershell -ExecutionPolicy Bypass -File scripts\deploy.ps1 # deploy only
powershell -ExecutionPolicy Bypass -File scripts\deploy.ps1 -StartSimHub # deploy + launch
# scripts\deploy.ps1 -DllOnly # plugin only, skip dashboards
# scripts\deploy.ps1 -DashboardsOnly # dashboards only, skip pluginEasier path: use the Quick install (installer) above. The manual steps below are for developers building from source.
- Close SimHub.
- Copy from
bin\Release\toC:\Program Files (x86)\SimHub\:F1SimHubLive.dll(required)Microsoft.AspNet.SignalR.Client.dll(required, ships with the plugin)Newtonsoft.Json.dll(only if SimHub doesn't already ship a compatible version)
- Copy
F1SimHubLive.Settings.example.jsonto that same folder asF1SimHubLive.Settings.json(next to the DLL). - Start SimHub. On first run it asks to enable the new plugin — say yes.
- Copy
dashboards/F1RaceSim_GSIFPEV2.djsonto:C:\Program Files (x86)\SimHub\DashTemplates\F1RaceSim_GSIFPEV2\F1RaceSim_GSIFPEV2.djson - Copy any background images referenced by the dashboard (V4 background, F1 logos, tyre icons) into the same folder.
- In SimHub → Dash Studio, open the F1RaceSim_GSIFPEV2 template.
- In your GSI wheel device profile, target the F1RaceSim_GSIFPEV2 dashboard.
F1SimHubLive.Settings.json (lives next to the DLL):
{
"DriverNumber": "44",
"OutputHz": 60,
"RenderDelayMs": 200,
"Source": "F1Live",
"MultiViewerBaseUrl": "http://localhost:10101",
"MultiViewerPollMs": 250,
"MultiViewerTimingPollMs": 1000,
"AutoLaunchPicker": false
}| Key | Default | Meaning |
|---|---|---|
DriverNumber |
"44" |
F1 racing number string. 44=Hamilton, 1=Verstappen, 16=Leclerc, 81=Piastri, 4=Norris, 63=Russell, 55=Sainz, 14=Alonso, 11=Pérez, 18=Stroll. Hot-reloadable in v1.1.0+ — changing this value (via JSON edit or the Driver Picker) is picked up by the plugin within ~250ms without restarting SimHub. |
OutputHz |
60 |
Interpolation tick rate for car telemetry. 60 is plenty for LEDs; higher just uses more CPU. |
RenderDelayMs |
200 |
Render lag. Holds 200ms of buffer so the interpolator always has prev + curr snapshots to interpolate between. Lower = less added latency but more "hold" between samples. |
Source |
"F1Live" |
F1Live (broadcast SignalR) or MultiViewer (local replay). |
MultiViewerBaseUrl |
http://localhost:10101 |
F1 MultiViewer HTTP API root. Only used when Source=MultiViewer. |
MultiViewerPollMs |
250 |
Car-data polling interval against MultiViewer (4 Hz default). |
MultiViewerTimingPollMs |
1000 |
Timing/session/weather polling interval against MultiViewer (1 Hz default). |
AutoLaunchPicker |
false |
When true, plugin spawns the Driver Picker every time SimHub starts. Off by default because the picker is admin-manifested and triggers a UAC prompt on each launch. Start Menu shortcut is the recommended manual-launch path. |
Hot-reloadable keys: DriverNumber only. All other keys still require a SimHub restart — changing URLs or polling intervals mid-session would require tearing down and re-establishing the client connection, and was intentionally left out of scope.
Live mode (default):
- F1 session is broadcasting on F1 TV.
Source=F1Livein settings.- Start SimHub → check Plugins panel → F1SimHubLive status should reach
Connected. - Properties populate within ~10s of session start.
Replay mode:
- Open F1 MultiViewer and sign in to F1 TV.
- Load the session you want to replay.
- Click "Replay Live Timing" on that session — this is the step that makes MultiViewer start emitting telemetry to
http://localhost:10101. Watching only the F1 video feed is not enough; the Live Timing view must be running. - Set
Source=MultiViewerin settings. - Restart SimHub.
- Scrub/play in MultiViewer; properties follow.
Verify the plugin is feeding properties (handy for debugging):
foreach ($p in 'Status','Rpm','Gear','Speed','Position','LapDisplay','TrackStatusCode','FlagText') {
$v = curl.exe -s "http://127.0.0.1:8888/api/getproperty/F1SimHubLivePlugin.$p"
Write-Host ("{0,-22} = {1}" -f $p,$v)
}(Requires SimHub's HTTP API enabled in Settings.)
Status stays Initializing or Connecting:
- F1Live: confirm an F1 session is actually broadcasting on F1 TV. Outside session windows the feed is empty.
- MultiViewer: confirm MultiViewer is running with a session loaded and Live Timing actively running. The fastest check: open
http://localhost:10101/api/v1/live-timing/SessionInfoin a browser — if it returns 404 or an empty body, Live Timing is not on. For replays, click "Replay Live Timing" on the session card inside MultiViewer; the video player alone does not emit telemetry. Seedocs/multiviewer-api.mdfor the full two-stage probe rationale and a step-by-step manual verification recipe.
Properties show but RPM/Gear stay at 0:
- The CarData topic is per-driver. Confirm
DriverNumbermatches a driver currently in the field. Spelling/case doesn't matter — F1 uses raw integers as strings.
Wheel LEDs blink white only — no RPM gradient:
- Your per-device LED configuration still references a legacy plugin name (
F1SimSubGSIPlugin.orF1SimHubGSIPlugin.) that no longer loads. Run the v1.0.3+ installer — it auto-rewires these references and creates asettings.json.preLedRewire-<stamp>backup. See LED config auto-rewire for the full mechanism. If you want to verify manually, search forF1SimSubGSIPlugin.orF1SimHubGSIPlugin.insideC:\Program Files (x86)\SimHub\PluginsData\Common\Devices\<your-guid>\settings.json— there should be zero matches after the rewire. - Also confirm a SimHub-recognized game is running. The default LED tree gates everything on
DataCorePlugin.GameRunning = 1, so the gradient won't fire from MultiViewer-only telemetry yet.
Shift lights look choppy:
- Lower
RenderDelayMstoward 100. Below 100 you'll start to see hold (one sample staying put) before the next arrives.
Dashboard widget shows nothing / --:
- If the widget is inside a Layer group (e.g.
IncidentData), the group'sVisibleflag overrides every child. Set the groupVisible:trueand let child bindings drive individual visibility. - Widget-level
"Visible":false(a static property) also overridesBindings.Visible. Set the static property totrueif you want a binding to control it.
Newtonsoft.Json version conflict on SimHub startup:
- Remove
Newtonsoft.Json.dllfromC:\Program Files (x86)\SimHub\and use the one SimHub ships.
Driver Picker shows no drivers / "Waiting for MultiViewer...":
- The picker polls
http://localhost:10101/api/v1/live-timing/DriverList. If MultiViewer isn't running or no session is loaded, the picker falls back to the bundled grid (last-known F1 25 lineup). To get the live grid, start MultiViewer with a session and click "Replay Live Timing" (same prerequisite as the plugin's MultiViewer source). - The picker polls every 5 seconds — give it that long after starting MV before assuming something's wrong.
Driver Picker shows drivers but they're in race-number order, not championship order:
- The championship sort needs
/api/v1/live-timing/ChampionshipPrediction, which MultiViewer only populates during/after race sessions. During qualifying-only replays, or for a season-opening race weekend, this endpoint returns 404 and the picker falls back to race-number order. Not a bug — confirmation that the fallback is working.
Picker click doesn't flip the wheel / shows green flash but plugin doesn't react:
- Confirm
F1SimHubLive.Settings.jsonactually changed (open it; check the newDriverNumbervalue). If the file didn't change, the picker hit a permission error — re-run it as admin (or use the Start Menu shortcut, which inherits the picker'srequireAdministratormanifest). - If the file DID change but the plugin didn't react, check SimHub's plugin log for
[F1SimHubLivePlugin]— the hot-reload writes a line likeDriver changed: 44 → 12. No line =FileSystemWatcherdidn't fire (rare, usually a path mismatch — verify the plugin and picker both point at the samesettings.jsonunderC:\Program Files (x86)\SimHub\).
Picker UAC prompt is annoying — can I turn it off?
- Not without recompiling the picker without the
requireAdministratormanifest. The manifest is required because the picker writes tosettings.jsoninsideProgram Files (x86)\SimHub\, which is admin-only. The cleanest "no UAC every launch" path is to leaveAutoLaunchPicker = false(default) and accept one UAC per picker launch.
%USERPROFILE%\F1SimHubLive\
├── F1SimHubLivePlugin.cs # Entry point; property registration + event wiring
├── Settings.cs # JSON settings model
├── F1SimHubLive.csproj # .NET 4.8 class library
├── F1SimHubLive.Settings.example.json
├── README.md # this file
├── F1Signalr/
│ ├── F1SignalRClient.cs # Live SignalR client (livetiming.formula1.com)
│ ├── CarDataDecoder.cs # base64 → DEFLATE → JSON → DriverSnapshot
│ └── TopicNames.cs
├── MultiViewer/
│ ├── MultiViewerHttpClient.cs # Local MultiViewer HTTP polling
│ ├── TimingDataDecoder.cs # Position/Gap/Sectors + Ahead/Leader car numbers
│ ├── TimingStatsDecoder.cs # TopSpeed + rank
│ ├── TimingAppDataDecoder.cs # Tyre + stops
│ ├── SessionDataDecoder.cs # Session clock
│ ├── TrackStatusDecoder.cs # Track status enum
│ ├── LapCountDecoder.cs # CurrentLap/TotalLaps
│ ├── WeatherDataDecoder.cs # Weather snapshot
│ ├── RaceControlDecoder.cs # FlagText
│ ├── DriverListDecoder.cs # driver # → metadata
│ └── ExtrapolatedClockDecoder.cs # Session clock fallback
└── Telemetry/
├── ITelemetrySource.cs # Common interface for both sources
├── DriverSnapshot.cs # RPM/Gear/Speed/etc — per car
├── TimingSnapshot.cs # Per-driver timing
├── SessionSnapshot.cs # Track status + session clock
├── WeatherSnapshot.cs
├── TelemetryBuffer.cs # Ring of prev + curr snapshots
└── Interpolator.cs # 60 Hz linear interpolation
installer/ # WPF installer wizard (.NET 8)
├── F1SimHubLive.Installer.csproj # Single-file publish; chain-publishes the picker
├── App.xaml / App.xaml.cs
├── MainWindow.xaml / MainWindow.xaml.cs # 4-step wizard UI
├── Models/ # F1Driver, PrereqResult
├── Services/ # PrereqChecker, DriverListService, Deployer
└── Assets/ # Embedded plugin DLL, dashboard, drivers-fallback.json
# (picker exe is also embedded at build time)
picker/ # Driver Picker — standalone WPF app (.NET 8)
├── F1SimHubLive.Picker.csproj # Single-file self-contained publish, admin manifest
├── App.xaml / App.xaml.cs
├── MainWindow.xaml / MainWindow.xaml.cs # Always-on-top driver grid UI
├── Models/
│ └── DriverEntry.cs # TLA / team colour / points view-model
├── Services/
│ ├── MultiViewerDriverListClient.cs # /DriverList + /ChampionshipPrediction
│ ├── SettingsFileWriter.cs # Writes DriverNumber to plugin settings.json
│ └── HexToBrushConverter.cs # XAML helper
├── Assets/
│ └── picker.ico # Multi-res app icon
└── app.manifest # requireAdministrator
dashboards/ # Source-of-truth Dash Studio templates
└── F1RaceSim_GSIFPEV2/ # Deployed by the installer to SimHub\DashTemplates\
scripts/
├── refresh-drivers.ps1 # Pull current grid from MultiViewer into drivers-fallback.json
└── install-picker.ps1 # Local-only deploy of the picker (skips full installer rebuild)
.github/workflows/
└── release.yml # Tag-triggered build + (optional) Trusted Signing
CHANGELOG.md # Version history
DASHBOARD.md # Widget-level reference for F1RaceSim_GSIFPEV2.djson
SIGNING.md # Code-signing options for the installer + picker
LICENSE # MIT
Dashboard template lives in SimHub's install dir (not this repo):
C:\Program Files (x86)\SimHub\DashTemplates\F1RaceSim_GSIFPEV2\
├── F1RaceSim_GSIFPEV2.djson # the dashboard definition
└── (background images, tyre icons, F1 logos)
The Driver Picker exe ALSO lands in the SimHub install dir alongside the plugin DLL (so it can read/write the plugin's settings.json without hardcoding a path):
C:\Program Files (x86)\SimHub\F1SimHubLive-Picker.exe
And a Start Menu shortcut is created in the All-Users Start Menu:
C:\ProgramData\Microsoft\Windows\Start Menu\Programs\F1SimHubLive\
└── F1SimHubLive Driver Picker.lnk
- No ERS state — lives in
TimingAppDatabut not yet decoded (v2candidate). - No track position —
Position.zexists in the feed but not parsed (could drive a circuit-map widget). - No settings GUI — edit JSON and restart SimHub.
- Live mode only works during active F1 sessions (FP1/2/3, Q, Sprint, Race). Outside that window the SignalR connection succeeds but no
feedmessages arrive. Use MultiViewer source for replay. - F1 broadcast telemetry is 3–10 Hz per car. No client can do better than that — the interpolator smooths it but doesn't add information.
- SC and RED flag visual states untested in production. The bindings use the same code paths as the confirmed YELLOW/VSC states; should work but unverified on live wheel.
Released under the MIT License — Copyright © 2026 Victor de Souza (@vicslive). Fork freely, contribute back if you'd like.
F1 live timing data is proprietary to Formula 1. This plugin is a fan tool and is not affiliated with Formula 1, F1 MultiViewer, SimHub, GSI, or any team.
| Doc | What's in it |
|---|---|
| CHANGELOG.md | Version history. v1.0.1 ships the verified 2026 grid; v1.0.0 was the first public installer. |
| DASHBOARD.md | Implementer's reference for F1RaceSim_GSIFPEV2.djson — every widget, binding, and the gotchas discovered while building it. |
| docs/multiviewer-api.md | Why "MultiViewer is open" is not enough — the API-up vs Live-Timing-streaming distinction, the two-stage Heartbeat+SessionInfo probe the installer uses, a 5-step manual verification recipe, and a reference table of every endpoint the plugin polls. |
| SIGNING.md | Code-signing options for the installer ranked by cost/UX. Includes the Microsoft Trusted Signing employee-credit path and the SFI workaround. |
| scripts/refresh-drivers.ps1 | Pulls the current season's DriverList from a running MultiViewer and rewrites installer/Assets/drivers-fallback.json. Run at the start of each season. |
| .github/workflows/release.yml | GitHub Actions release pipeline — builds the installer on every v*.*.* tag, signs it via azure/trusted-signing-action if signing secrets are configured. |
PRs, issue reports, and forks are welcome. See CONTRIBUTING.md for the development setup, what's in/out of scope, and the PR checklist.
- SimHub by Wotever — the platform that makes wheel telemetry possible.
- F1 MultiViewer — the inspiration for replay-mode support and the source-of-truth for the broadcast topics.
- FastF1 — invaluable reference for the CarData channel numbering and SignalR topic semantics.
- GSI (Gomez Sim Industries) — the Formula Pro Elite V2 wheel this was built around.
Built by Victor de Souza (@vicslive) — personal hack to make F1 broadcasts more immersive on the rig.

