RaceLink Standalone Guide¶
This guide explains how to install and run racelink-host in standalone mode on Windows and Linux.
Standalone mode runs the RaceLink host runtime and the shared RaceLink WebUI without RotorHazard. It is intended for gateway-backed operation, so a connected RaceLink Gateway is expected for normal use.
Requirements¶
- Python
3.10or newer - A terminal or shell
- A RaceLink Gateway connected by USB for normal operation
- Network access to install Python packages
The packaged standalone entrypoint is:
Default standalone URL:
Get the release wheel¶
racelink-host is published as a GitHub release artifact (not on PyPI).
Download the wheel for the version you want from the project's releases
page:
Save racelink_host-<version>-py3-none-any.whl and note its path — the
install commands below reference that file. (For the offline .tar.gz
bundle and the release/build flow, see the Host README.)
Windows installation and usage¶
These steps use a folder named RaceLink in your user directory
(C:\Users\<your-name>\RaceLink). You can pick another location — just
use the same folder for every command.
Step 1 — Create the folder and put the wheel in it.
Open File Explorer, go to your user folder, create a new folder named
RaceLink, and move the downloaded
racelink_host-<version>-py3-none-any.whl (from the releases
page) into it.
Step 2 — Open PowerShell inside that folder.
Open the RaceLink folder in File Explorer, click the address bar, type
powershell, and press Enter. PowerShell opens already pointed at the
folder.
Edit the command before running it
In the block below, replace <version> with the version you
downloaded — e.g. for racelink_host-0.1.6-py3-none-any.whl use
0.1.6. If you chose a folder other than
C:\Users\<your-name>\RaceLink, also adjust the cd path.
Step 3 — Install:
cd $env:USERPROFILE\RaceLink
py -3 -m venv .venv
.venv\Scripts\Activate.ps1
python -m pip install --upgrade pip
python -m pip install .\racelink_host-<version>-py3-none-any.whl
racelink-host is distributed as a GitHub release artifact (not PyPI),
so this installs the downloaded .whl directly; its runtime
dependencies (Flask, pyserial) come from PyPI.
If activation is blocked by the execution policy
On a fresh Windows install the default PowerShell execution policy
blocks Activate.ps1 with a security error. Allow signed scripts for
the current session, then re-run the whole block from Step 3:
Step 4 — Start RaceLink and open the UI:
--open-browser opens http://127.0.0.1:5077/racelink in your default
browser once the server is ready. Leave the PowerShell window open while
you use RaceLink; press Ctrl+C (or close the window) to stop it.
On later runs you only re-activate and start — no reinstall:
Create a desktop shortcut (Windows)¶
So you can launch RaceLink with a double-click, create a file
RaceLink.bat in your RaceLink folder. In Notepad, paste the lines
below, then Save As → set Save as type to All files → name it
RaceLink.bat:
@echo off
cd /d "%USERPROFILE%\RaceLink"
call .venv\Scripts\activate.bat
racelink-standalone --open-browser
Double-clicking RaceLink.bat now starts the server and opens the WebUI
automatically (the .bat uses the cmd activation, so the PowerShell
execution-policy note above does not apply). To put it on the desktop,
right-click RaceLink.bat → Show more options → Send to → Desktop
(create shortcut). A small console window stays open while RaceLink
runs — closing it stops the server.
Windows notes:
- The RaceLink Gateway appears as a
COMport, typically aSilicon Labs CP210x USB to UART Bridge(for exampleCOM12); check Device Manager if you are unsure which port it is - You normally do not need to configure the port. On startup the host probes every USB serial port and auto-attaches any gateway that answers the identify handshake — see Gateway detection and reconnect
- Set
rl_comms_port(see Configuration file) only to pin one specific device, for example when several serial adapters are attached
Windows firmware updates (WLED OTA)¶
WLED node firmware updates are supported on Windows. The host drives its
own WiFi via netsh wlan to connect to each node's SoftAP, push the
firmware/config over HTTP, and disconnect again — the Windows equivalent
of the Linux nmcli flow.
Prerequisite: enable Windows Location Services
On Windows 10/11 the netsh wlan APIs only expose WiFi network
names (SSIDs) when Location Services is enabled — this applies to
both scanning and reading the currently-connected SSID. With
Location off, the host can neither find the WLED access point nor
confirm a connection, and the update fails with "could not connect …
no association within window" even though Windows briefly associates.
Enable it once under Settings → Privacy & security → Location
(shortcut: paste ms-settings:privacy-location into the address bar
or the Win+R Run box): turn on Location services and Let
desktop apps access your location. RaceLink detects this state and
fails fast with the same instruction (including the shortcut) instead
of timing out.
This is a global / device-level Windows setting — it cannot be granted
to RaceLink alone. Per-app location toggles only exist for Store/UWP
apps; classic desktop apps (like racelink-standalone) are all
covered by the single "Let desktop apps access your location" switch.
Other Windows specifics:
- The WLAN adapter must be enabled. The host connects using the already-on adapter. If the adapter is disabled, enabling it from within RaceLink requires running the host as Administrator — easier to just switch WiFi on in Windows first.
- A "sign in to the network" / captive-portal browser tab may pop up. When Windows joins the WLED AP it probes for internet, finds none, and may open a browser (e.g. an MSN sign-in page). This is normal Windows behaviour and does not affect the update — the host still reaches the node at its AP address. You can close the tab.
- No BSSID targeting.
netshconnects by SSID only and cannot pin a specific access point. If several nodes broadcast the same AP SSID, Windows may associate with the wrong one. Flash such fleets one node at a time, or give each node a unique AP SSID. (Single-node OTA is unaffected.) - Tip: if your node uses only one of the default SSIDs, set that one explicitly in the Firmware Update dialog. The host tries each candidate SSID in turn, so trimming the list skips a wasted connect attempt on the SSID your node doesn't broadcast.
- The Firmware Update dialog's WLED-AP SSID/password defaults
(
WLED_RaceLink_AP, WLED-AP/wled1234) apply the same as on Linux; both WPA2 and open WLED APs are handled.
Connecting to a WLED AP and other network traffic
Joining a WLED SoftAP (which has no internet) can make Windows
juggle connections: you may see the WiFi status flip between
connecting / available / disconnected, and historically — when
the RaceLink WebUI was served from a separate machine (e.g. a
RotorHazard Raspberry Pi on Ethernet) — the operator PC connecting
its WiFi to a WLED hotspot could stall that remote WebUI until the
WiFi was disconnected. Running racelink-standalone locally on
the same PC avoids this: the WebUI is served over loopback
(127.0.0.1) and is unaffected by WiFi routing. If association
still won't hold, temporarily disconnect/forget any nearby
internet WiFi so Windows can't roam away from the no-internet WLED
AP during the update.
Linux installation and usage¶
These steps use a folder named racelink in your home directory
(~/racelink). You can pick another location — just use the same folder
for every command.
Step 1 — Create the folder and put the wheel in it.
Then download / move racelink_host-<version>-py3-none-any.whl
(from the releases page) into ~/racelink.
Edit the command before running it
In the block below, replace <version> with the version you
downloaded — e.g. for racelink_host-0.1.6-py3-none-any.whl use
0.1.6. If you chose a folder other than ~/racelink, also adjust
the paths.
Step 2 — Install:
cd ~/racelink
python3 -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade pip
python -m pip install ./racelink_host-<version>-py3-none-any.whl
racelink-host is distributed as a GitHub release artifact (not PyPI),
so this installs the downloaded .whl directly; its runtime
dependencies (Flask, pyserial) come from PyPI.
Step 3 — Start RaceLink and open the UI:
--open-browser opens http://127.0.0.1:5077/racelink in your default
browser once the server is ready. Leave the terminal open while you use
RaceLink; press Ctrl+C to stop it.
On later runs you only re-activate and start — no reinstall:
Create a desktop shortcut (Linux)¶
Create a launcher script ~/racelink/racelink.sh:
cat > ~/racelink/racelink.sh <<'EOF'
#!/usr/bin/env bash
cd "$HOME/racelink" || exit 1
source .venv/bin/activate
exec racelink-standalone --open-browser
EOF
chmod +x ~/racelink/racelink.sh
Then create a desktop entry so it shows up in your application menu.
Replace YOUR_HOME with the output of echo $HOME (desktop files do not
expand $HOME in Exec):
mkdir -p ~/.local/share/applications
cat > ~/.local/share/applications/racelink.desktop <<'EOF'
[Desktop Entry]
Type=Application
Name=RaceLink Host
Comment=Start RaceLink Host and open the WebUI
Exec=YOUR_HOME/racelink/racelink.sh
Terminal=true
Categories=Utility;
EOF
Terminal=true keeps a window open showing logs; closing it stops the
server. Most desktops also let you copy the .desktop file to your
Desktop to get a clickable icon there.
Linux notes:
- The RaceLink Gateway usually appears as a serial device such as
/dev/ttyUSB0or/dev/ttyACM0 - If RaceLink cannot open the gateway, check user permissions for serial devices
- On some systems you may need to add the user to a group such as
dialout - Wi-Fi helper features that depend on
nmclionly work in environments where NetworkManager andnmcliare installed
Linux first-time setup for firmware updates¶
The OTA flow connects the host's WiFi directly to a WLED node's AP via
nmcli dev wifi connect <SSID> password <PASS> and disconnects it
afterwards. No pre-created NetworkManager profile is required — NM
creates one persistent profile per SSID on first connect and reuses it
on subsequent runs.
The nmcli command needs polkit authorisation. On a fresh Linux host,
run the bundled setup helper once as root to grant the running user
unattended access:
sudo apt install network-manager # Debian/Ubuntu/Pi OS only
sudo $(which racelink-setup-nmcli) # absolute path; see below
# restart the host (RotorHazard or racelink-standalone) so the running
# Python process re-establishes its polkit subject
racelink-setup-nmcli is shipped as a console script alongside
racelink-standalone, so a pip install racelink-host puts it on the
host's PATH. Use sudo $(which racelink-setup-nmcli) rather than
the bare command — sudo's default secure_path strips the venv's
bin/ directory, so sudo racelink-setup-nmcli fails with
command not found on piwheel / venv installs (the typical
RotorHazard plugin layout). The OTA failure dialog also surfaces the
exact absolute command for the install you're running, so you can
copy-paste it directly from the toast if which isn't on your PATH
either.
The helper is idempotent: adds the user to the netdev (or wheel
on Fedora/RHEL) group and installs a polkit rule at
/etc/polkit-1/rules.d/49-racelink-nmcli.rules that authorises
org.freedesktop.NetworkManager.* actions for that specific user.
Verify with nmcli dev wifi list — if it lists nearby APs without
prompting for a password, the host is ready.
If you've cloned the source repo instead of installing via pip, the
equivalent bash variant lives at scripts/setup_nmcli_polkit.sh and
writes the same polkit rule.
The Firmware Update dialog ships sensible defaults (SSID list
WLED_RaceLink_AP, WLED-AP, password wled1234). Override per-OTA if
your fleet uses a custom WLED AP password.
Configuration file¶
Standalone mode stores its local configuration in:
On Windows this usually expands to something like:
On Linux this usually expands to something like:
Upgrading from an older install
Earlier versions used unprefixed names (standalone_config.json,
scenes.json, and a presets/ folder). On first start the host
renames them to the rl_-prefixed scheme automatically — no manual
migration needed.
Example configuration:
Useful fields:
host: bind address for the standalone Flask serverport: TCP port for the standalone Flask serverdebug: Flask debug modeoptions: persisted RaceLink options used by the host runtimeoptions.rl_comms_port: optional serial-port pin. Leave it unset to use automatic gateway discovery. Accepts:- a single port (
"COM12"on Windows,"/dev/ttyUSB0"on Linux) — pins that one device and skips the discovery probe - a comma-separated list (
"COM12,COM13") — multi-gateway pin: discovery runs, but only the listed ports are attached. Use this to bind a specific set of gateways in a multi-gateway rig and ignore any other RaceLink gateway that happens to be plugged in
- a single port (
To change the bind address or port, edit the config file before starting racelink-standalone.
The file is created automatically on first run, so you usually do not
need to write it by hand. rl_comms_port is shown above only to
illustrate the optional pin — it is not required for normal operation.
File locations¶
All persistent data lives under the per-user RaceLink directory
~/.racelink/. ~ expands to %USERPROFILE% on Windows and $HOME on
Linux.
| Contents | Path (under ~/.racelink/) |
|---|---|
| Standalone configuration | rl_standalone_config.json |
| Scenes | rl_scenes.json |
| RaceLink presets | rl_presets.json |
| Uploaded WLED preset files | rl_wled_presets/ |
Uploaded firmware (.bin) and config/preset files for OTA are not
kept under ~/.racelink/. They are staged in the operating system's
temporary directory and are disposable (cleared on reboot / temp
cleanup):
Logs: standalone mode logs to the terminal (stdout/stderr) where you
started racelink-standalone at INFO level — it does not write a log
file. Set RACELINK_LOG_LEVEL=DEBUG for verbose traces (useful when
diagnosing gateway or OTA issues). To keep a log, redirect the console
output yourself, for example:
(When RaceLink runs as the RotorHazard plugin instead of standalone, logging is handled by RotorHazard's own logging system.)
Verifying that standalone mode works¶
After starting the server:
- Open
http://127.0.0.1:5077/ - Confirm it redirects to
/racelink - Confirm the RaceLink WebUI loads successfully
- Watch the terminal output for gateway startup messages
Expected behavior:
- Without a connected gateway, the UI can still load, but gateway communication will not be ready
- With a connected gateway, standalone mode should report that the communicator is ready and the WebUI should be able to interact with RaceLink services
Gateway detection and reconnect¶
The host finds the gateway automatically: on startup it probes every
USB serial port, sends an identify handshake, and attaches any port that
answers as a RaceLink gateway. Every responding gateway is attached, so
a multi-gateway setup works out of the box. When it succeeds, the WebUI
shows the gateway as connected (state bound) and the master bar
reports the network as ready.
To restrict which gateways are attached, set rl_comms_port (see
Configuration file): a single port pins exactly
that device and skips the probe; a comma-separated list ("COM12,COM13")
attaches only the listed gateways while ignoring any others.
If the gateway is not detected right after startup
Opening the USB serial port toggles the adapter's reset line, which
reboots the gateway. If the startup probe lands while the gateway is
still booting, the first attempt reports
No RaceLink Gateway module discovered or configured. A missing
gateway (NOT_FOUND) is not retried automatically, because that
state normally means no hardware is present. Once the gateway has
finished booting, trigger a manual reconnect from the WebUI (the
gateway/reconnect control in the master bar) and it attaches within
a second. This is expected on the first launch after plugging in the
gateway.
Manual validation checklist¶
- Create a fresh virtual environment
- Install
racelink-hostfrom the release wheel - Start
racelink-standalone - Open the browser at
/racelink - Confirm
/redirects to/racelink - Confirm the shared RaceLink WebUI loads
- Confirm the gateway is reported as unavailable when no gateway is connected
- Connect the gateway and confirm it is auto-detected (or attaches after a manual reconnect if the first startup probe caught it mid-boot)