Windows bridge for forwarding KMTronic relay commands to a Devantech USB-RLY02-SN.
This project exists to solve a protocol compatibility problem:
- Virtuagym expects to talk to a KMTronic-style USB relay over a serial COM port.
- Your hardware is a Devantech USB-RLY02-SN, which uses a different command set.
Because of that mismatch, Virtuagym cannot directly control the relay board. This script acts as a protocol translator in the middle.
At runtime, the script behaves like this:
- Virtuagym sends KMTronic commands to a virtual COM port.
- This script opens the other side of that virtual COM pair and receives those bytes.
- It parses the KMTronic frames and translates them to Devantech USB-RLY02-SN commands.
- It sends translated commands to the real USB-RLY02-SN COM port.
- For status requests, it reads the actual Devantech relay states and replies back in KMTronic-compatible format.
In short: Virtuagym thinks it is talking to KMTronic hardware, but this bridge quietly converts everything so a Devantech USB-RLY02-SN is controlled instead.
The bridge currently supports KMTronic command frames that are 3 bytes long and start with FF.
| KMTronic input | Meaning | Devantech command sent |
|---|---|---|
FF 01 01 |
Relay 1 ON | 0x65 |
FF 01 00 |
Relay 1 OFF | 0x6F |
FF 02 01 |
Relay 2 ON | 0x66 |
FF 02 00 |
Relay 2 OFF | 0x70 |
FF 01 03 |
Request status relay 1 | Sends 0x5B, then returns KMTronic reply |
FF 02 03 |
Request status relay 2 | Sends 0x5B, then returns KMTronic reply |
FF 09 00 |
Request all statuses | Sends 0x5B, then returns --km-status-count bytes |
- Single relay status request (
FF <relay> 03) returnsFF <relay> <state><state>is01for ON and00for OFF.
- Multi-status request (
FF 09 00) returns a byte array where each byte is01or00.- Number of bytes is controlled by
--km-status-count.
- Number of bytes is controlled by
--relay-mapcontrols how KMTronic relay numbers map to physical Devantech relays.- Example:
1:1,2:2means KM relay 1 controls Dev relay 1, KM relay 2 controls Dev relay 2.
- Example:
--km-status-countcontrols how many bytes are returned forFF 09 00.- Use this to match what the upstream software expects (for example 1, 2, 4, or 8 bytes).
- If a command targets a KMTronic relay that is not present in
--relay-map, the script logs a warning and skips switching. - If the Devantech relay COM port disappears, write/read errors are logged, the bad serial handle is closed, and the script keeps retrying the port instead of exiting.
- If Devantech state polling fails or times out, the script falls back to cached relay state so status replies still work.
- If the virtual KMTronic COM port disappears or is temporarily unavailable, the script keeps retrying it instead of exiting.
- If an unexpected internal error happens, the main loop logs it and restarts the bridge object automatically.
- Unknown KMTronic commands are ignored with a warning instead of crashing the process.
- Relay commands that arrive while the Devantech board is disconnected cannot be physically executed. They are logged and are not replayed later, so an old check-in command cannot unexpectedly switch the relay after the hardware comes back.
- The script does not create COM ports; it requires an existing virtual COM pair (for example com0com).
- It is not a generic serial sniffer.
- It does not include relay scheduling or business logic.
- It does not expose a web API.
- It is not tied to Virtuagym only, but it is designed specifically for software that speaks KMTronic serial protocol.
- Python 3.12 or newer installed on Windows.
pyserialinstalled in the Python environment you will use.- A USB-RLY02-SN relay board connected by USB and visible as a COM port.
- A virtual COM port pair on Windows, for example created with com0com:
- One virtual port is used by Virtuagym.
- The other virtual port is used by this bridge.
-
Open PowerShell in this folder.
-
Create a virtual environment:
python -m venv .venv -
If PowerShell blocks script activation, allow it for this terminal session:
Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass
-
Activate the virtual environment:
.\.venv\Scripts\Activate.ps1
If you prefer the batch activator, use:
cmd /c .venv\Scripts\activate.bat
-
Install dependencies:
pip install pyserial
Python cannot create Windows COM ports by itself, so create a paired virtual serial link with a tool such as com0com.
By default, com0com creates a COM5 <-> COM6 pair.
Example pair:
COM5<->COM6
Then assign the ports like this:
- Virtuagym uses
COM5 - This bridge listens on
COM6 - The USB-RLY02-SN uses its real device COM port, for example
COM7
From this folder, with the venv activated, run. Adjust the COM ports to match your own virtual COM pair and USB relay device:
python translator.py --listen-port COM6 --devantech-port COM4 --relay-map 1:1,2:2 --km-status-count 2 --log-file translator.log --verboseIf Virtuagym only uses one relay channel, run:
python translator.py --listen-port COM6 --devantech-port COM4 --relay-map 1:1 --km-status-count 1 --log-file translator.log --verbose--listen-port: virtual COM port opened by this script.--devantech-port: real COM port of the USB-RLY02-SN.--relay-map: maps KMTronic relay numbers to Devantech relays.--km-status-count: how many status bytes to return for aFF 09 00request. Must be between1and64.--listen-timeout: serial read timeout for the virtual KMTronic COM port. Default:0.1.--devantech-timeout: serial read timeout for the Devantech COM port. Default:0.5.--reconnect-delay: seconds between COM port reconnect attempts. Default:2.--log-file: optional rotating log file for unattended production runs.--verbose: enables debug logging.
- Start the bridge.
- Open Virtuagym and trigger a relay action.
- Confirm the matching relay on the USB-RLY02-SN turns on or off.
- If status polling is used, confirm the reported relay state matches the physical board.
- For a production reliability check, unplug the USB-RLY02-SN briefly, plug it back in, and confirm the script logs the disconnect/reconnect without exiting.
If nothing happens, check these first:
- The virtual COM pair is connected correctly.
- Virtuagym is pointed at the correct side of the pair.
- The USB-RLY02-SN COM port is correct.
- No other program is already using either COM port.
- The
translator.logfile if you started the bridge with--log-file.
The simplest reliable way on Windows is Task Scheduler.
-
Open Task Scheduler.
-
Create a new task.
-
On the General tab, choose a name such as
KMTronicToDevantechCommandTranslator. -
Select
Run only when user is logged onif you want to keep it simple, orRun whether user is logged on or notif you want it to start in the background. -
On the Triggers tab, add a trigger for
At log onorAt startup. -
On the Actions tab, add one action:
-
Program/script:
C:\Windows\System32\cmd.exe -
Add arguments. Replace the project path and COM ports with values for your machine:
/c "cd /d C:\Path\To\KMTronicToDevantechCommandTranslator && .venv\Scripts\activate.bat && python translator.py --listen-port COM6 --devantech-port COM7 --relay-map 1:1,2:2 --km-status-count 2 --log-file translator.log --verbose"
-
-
On the Settings tab, enable
If the task fails, restart everyand choose a short interval such as1 minute. -
Save the task.
-
Reboot and confirm the bridge starts automatically.
For easier maintenance, you can create a small batch file later and point Task Scheduler at it. That keeps the command line short and makes port changes easier to edit.
Example contents for a future start-translator.bat:
@echo off
cd /d C:\Path\To\KMTronicToDevantechCommandTranslator
call .venv\Scripts\activate.bat
python translator.py --listen-port COM6 --devantech-port COM7 --relay-map 1:1,2:2 --km-status-count 2 --log-file translator.log --verbose- If Windows assigns different COM numbers after reconnecting hardware, update the command accordingly.
- Keep the virtual COM pair and the USB-RLY02-SN COM port fixed if possible.
- The bridge logs to the console and, when
--log-fileis used, also writes a rotating log file with up to 5 files of about 1 MB each.