This guide explains how to route isiMotor-Pulse-Plugin telemetry streams across different network topologies using its ZeroMQ PUB/SUB transport over TCP: Local Loopback, LAN, Multiple Simultaneous Consumers, and Public IP / Internet (Remote Pit-Wall / Telemetry Engineers).
- How the Transport Works (PUB/SUB, Bind vs Connect)
- Local Loopback (Same PC)
- LAN — Wi-Fi Tablet or Dashboard Device
- Multiple Simultaneous Consumers
- Streaming Over Public IP / Internet / 4G (Remote Telemetry)
- Firewall & Troubleshooting Checklist
The plugin uses ZeroMQ PUB/SUB, on TCP only (no UDP, no multicast/broadcast transport). Each outbound packet type is published on its own PUB socket and its own port (TcpBasePort + packetType), so a consumer can connect to only the stream(s) it needs — ports are hardcoded arithmetically for now, pending a future service registry that will allocate them dynamically:
| Channel | Plugin role | Client role | Config keys | Ports |
|---|---|---|---|---|
| Outbound telemetry (one port per packet type) | PUB, binds | SUB, connects | TcpHost / TcpBasePort |
5001–5010 (base 5000 + type; see table below) |
| Inbound commands (hardware controls, weather overrides, grouped) | SUB, binds | PUB, connects | InboundTcpHost / InboundTcpPort |
5101 |
| Type | Packet | Port (TcpBasePort + type) |
|---|---|---|
| 1 | TelemInfo |
5001 |
| 2 | CompactScoring |
5002 |
| 3 | SystemEvent |
5003 |
| 4 | FullScoringSession |
5004 |
| 7 | WeatherControl |
5007 |
| 8 | ExtendedState |
5008 |
| 9 | ForceFeedback |
5009 |
| 10 | Graphics |
5010 |
The plugin is always the side that binds (it is the long-lived process for the duration of a session); every consumer — a dashboard, an overlay, the Manager — connects as a client. Because PUB/SUB natively supports any number of subscribers on one bound endpoint, there is no separate multicast group or broadcast address to configure: adding a second consumer to a given packet type is just opening a second connection to the same TcpHost:<base+type>.
Note on the "slow joiner" behavior: a SUB socket that has just connected can miss the very first message or two published right after connecting, until its subscription has propagated back to the PUB. This is a normal ZeroMQ characteristic (not a bug) and is harmless for a continuous telemetry stream — the next tick arrives a few milliseconds later.
For dashboards, overlays, or SimHub-style apps running on the same PC as the game:
{
"isiMotor_Pulse": {
"TcpHost": "127.0.0.1",
"TcpBasePort": "5000"
}
}Zero further configuration required. Any local Python client just does:
from isimotor_pulse_client import IsiMotorClient
client = IsiMotorClient(host="127.0.0.1", base_port=5000)
client.start()To let a device elsewhere on the LAN (a tablet, a second PC) connect to the telemetry stream, bind the plugin's PUB socket on all interfaces (or its specific LAN IP) instead of loopback-only:
{
"isiMotor_Pulse": {
"TcpHost": "0.0.0.0",
"TcpBasePort": "5000"
}
}On the receiving device, connect a SUB client to the game PC's LAN IP:
client = IsiMotorClient(host="192.168.1.42", base_port=5000) # game PC's LAN IP
client.start()TCP handles retransmission and flow control itself, so there is no Wi-Fi-specific tuning needed (unlike UDP multicast/broadcast, which is sensitive to IGMP snooping and beacon rates on wireless networks).
Because the plugin's telemetry socket is a ZeroMQ PUB, any number of SUB clients can connect to it at once — a motion rig, SimHub, a dashboard, and the Manager can all subscribe simultaneously without any extra plugin-side configuration:
{
"isiMotor_Pulse": {
"TcpHost": "0.0.0.0",
"TcpBasePort": "5000"
}
}Each consumer independently does:
client_a = IsiMotorClient(host="192.168.1.10", base_port=5000) # motion rig
client_b = IsiMotorClient(host="192.168.1.10", base_port=5000) # SimHub bridge
client_c = IsiMotorClient(host="192.168.1.10", base_port=5000) # dashboard tabletThere is no practical limit imposed by the plugin; ZeroMQ's PUB socket fans the same message out to every connected subscriber.
The safest and simplest option for a remote pit-wall or coach setup: install Tailscale (or WireGuard) on both the game PC and the remote engineer's machine. They get a private, encrypted 100.64.x.x-range IP that behaves like a LAN address, with no port forwarding or public exposure.
{
"isiMotor_Pulse": {
"TcpHost": "0.0.0.0",
"TcpBasePort": "5000"
}
}The remote engineer connects using the game PC's Tailscale IP:
client = IsiMotorClient(host="100.64.1.25", base_port=5000)If a VPN is not an option, you can expose the PUB endpoint directly over public IPv4 via router port forwarding:
┌──────────────────────┐ Internet ┌──────────────────────┐ Port Forward ┌──────────────────────┐
│ Sim Racer PC │ ────────────────────> │ Remote Router Box │ ──────────────────> │ Remote Engineer PC │
│ TcpHost=0.0.0.0 │ (Public WAN) │ Public IP: 82.64.x.y │ TCP Ports 5001-5010 │ SUB connects here │
└──────────────────────┘ └──────────────────────┘ └──────────────────────┘
- On the Sim Racer PC's router: add Port Forwarding (NAT) rules forwarding TCP ports
5001–5010(whichever packet types the remote client needs) to the sim PC's LAN IP. - Find the Sim Racer PC's public IP: visit
https://ifconfig.mefrom that PC. - On the remote engineer's client: connect to that public IP:
client = IsiMotorClient(host="82.64.x.y", base_port=5000)
Caution: Direct TCP port forwarding exposes that port to the open internet. Anyone knowing the public IP can open a ZeroMQ SUB connection to the stream. For secure long-term remote team telemetry, Method A (Tailscale/VPN) is strongly advised.
For multi-viewer web dashboards or race broadcast overlays, run a small relay process that connects to the plugin as a regular SUB client, then re-publishes over WebSockets to browsers:
┌─────────────┐ ZeroMQ PUB/SUB ┌───────────────────────────┐ WebSockets / HTTP ┌───────────────────┐
│ Sim Game PC │ ───────────────────> │ Cloud VPS (Relay Server) │ ────────────────────> │ 100+ Web Viewers │
└─────────────┘ │ Python (isimotor client) │ │ Browser Overlays │
└───────────────────────────┘ └───────────────────┘
The relay connects IsiMotorClient(host="<sim-pc>", base_port=5000) and forwards decoded packets (JSON or compact binary frames) to browsers over WebSockets.
If remote/LAN consumers cannot connect:
New-NetFirewallRule -DisplayName "isiMotor ZeroMQ Telemetry (5001-5010)" -Direction Inbound -LocalPort 5001-5010 -Protocol TCP -Action Allow
New-NetFirewallRule -DisplayName "isiMotor ZeroMQ Inbound Commands (5101)" -Direction Inbound -LocalPort 5101 -Protocol TCP -Action Allowsudo ufw allow 5001:5010/tcp
sudo ufw allow 5101/tcp- Verify the plugin's PUB sockets are listening on their per-type ports:
- Windows:
netstat -ano | findstr :5001 - Linux:
ss -tlnp | grep -E ":50(0[1-9]|10)"
- Windows:
- Inspect the live stream with the Manager:
isi-manager --host 127.0.0.1 --port 5000
- Sniff the raw TCP handshake/traffic (payload itself is ZeroMQ-framed binary, not human-readable):
sudo tcpdump -i any -n tcp portrange 5001-5010 -X