st-uhubm
A Python library, command-line tool, and web GUI for managing StarTech Managed Industrial USB Hubs on Linux.
Unofficial. This project is not affiliated with, endorsed by, or supported by StarTech.com. “StarTech” is a trademark of its respective owner. This package is a wrapper around StarTech’s own
cusbi/cusbabinary, which you must obtain separately (see Prerequisites). The binary is proprietary and is not redistributed here.
What is it
StarTech’s USB hubs expose a serial control channel (it enumerates as
/dev/ttyUSB<n>) that lets user switches individual downstream ports on and off,
reboot the hub, and persist a default port state. StarTech ships a control
binary (cusbi on x86/AMD64, cusba on ARM) to drive that channel.
st-uhubm wraps that binary with:
a Python API for scripting and integration;
a ``stuhubm`` CLI with subcommands and optional JSON output;
an optional ``stuhubm-gui`` NiceGUI web GUI with port toggles.
Supported hardware
Model |
Ports |
Notes |
|---|---|---|
|
7 |
7-port managed industrial hub |
|
4 |
4-port managed industrial hub |
Multiple hubs (including daisy-chained units) on one host are supported; each gets its own control port. Firmware v04 or newer is required.
This package controls hubs via StarTech’s serial protocol. It is not
uhubctland does not use USB per-port power switching (PPPS). The two are different projects.
Prerequisites
Python 3.10 or newer.
The StarTech binary, obtained from StarTech (see below). The correct binary for user’s CPU:
cusbi— Intel/AMD (x86-64) Linux hostscusba— ARM Linux hosts (e.g. Raspberry Pi, most SBCs)
Root access. The binary opens the control tty directly and requires root. Run as root, use
sudo, or grant access to the device via a udev rule / group membership (see Running without root).
Obtaining the vendor binary
This package does not redistribute StarTech’s proprietary binary. To obtain it:
Go to the product page for your model (
startech.com/5G7AINDRM-USB-A-HUBorstartech.com/5G4AINDRM-USB-A-HUB) and open the Drivers & Downloads tab.Download the Linux package (a tarball such as
cusbi-r1.02.tar.gz).Extract it and place the binary somewhere on your
PATH, e.g.:tar xzf cusbi-r1.02.tar.gz sudo install -m 0755 cusbi /usr/local/bin/cusbi
On ARM, do the same with
cusba.
Verify the package can see it:
stuhubm health
Installation
Core library and CLI:
pip install st-uhubm
With the web GUI:
pip install "st-uhubm[gui]"
As an isolated tool (recommended for CLI-only use):
pipx install st-uhubm
# or
uv tool install st-uhubm
Installing the package does not install the StarTech binary, that is a separate manual step (see Prerequisites).
Quick start
# 1. Confirm the binary is working and list hubs
stuhubm health
# 2. Discover connected hubs
stuhubm list
# 3. Show the port states of a hub
stuhubm status /dev/ttyUSB0
# 4. Turn port 3 off, then back on
stuhubm off /dev/ttyUSB0 3
stuhubm on /dev/ttyUSB0 3
# 5. Turn several ports off at once
stuhubm off /dev/ttyUSB0 3,4,5
# 6. Persist the current state so it survives a power cycle
stuhubm save /dev/ttyUSB0
If sudo prompts for a password on each call, see
Running without root.
Core concepts
Control port. Each hub is addressed by the serial device it enumerates as.
Pass exactly what stuhubm list reports for the hub, e.g. /dev/ttyUSB0.
Ports. Downstream USB-A ports are numbered from 1. User can act on a single
port (3), a comma-separated list (3,4,5), or all ports (all).
Port state. Each port is simply on or off. stuhubm status reports
the current state of every port.
Volatile vs. persistent. By default, changes are volatile — they apply immediately but are lost when the hub loses power or is reset. To make a state the power-on default, either:
pass
--persist(writes each change straight to the hub’s flash), ormake your changes volatile, then run
stuhubm saveonce to commit the current state to flash.
Prefer the second pattern for test rigs: it avoids a flash write on every toggle.
Password. Hubs ship with the default password pass. While the password is
unchanged from default, you do not need to supply it. Once you set a custom
password, every state-changing command must include it (via --password or the
STUHUBM_PASSWORD environment variable). Passwords are at most 8 characters.
Command-line interface (stuhubm)
General form:
stuhubm [global options] <command> [arguments]
Commands
Command |
Description |
|---|---|
|
Check that the binary is present and list detected hubs |
|
Discover hubs and show control port, model, serial, port count, firmware |
|
Show on/off state of every port on a hub |
|
Turn the given port(s) on |
|
Turn the given port(s) off |
|
Invert the given port(s) |
|
Turn all ports on or off |
|
Save current port states to flash (power-on default) |
|
Hardware-reset the hub |
|
Restore factory defaults (all ports on,
password |
|
Change the hub password (prompts interactively) |
PORTS is a single port (3), a comma-separated list (3,4,5), or
all.
Global options
Option |
Env var |
Default |
Meaning |
|---|---|---|---|
|
|
|
Control binary name or full path |
|
|
|
Run the binary
via |
|
|
(none) |
Hub password, if changed from default |
|
|
off |
Write changes to flash immediately |
|
— |
off |
Emit machine-readable JSON instead of text |
|
— |
|
Per-command timeout in seconds |
|
— |
off |
Print the exact binary invocation |
Examples
# Use the ARM binary at a specific path, no sudo (already root)
stuhubm --binary /opt/startech/cusba --no-sudo list
# JSON output for scripting
stuhubm --json status /dev/ttyUSB0
# -> {"port": "/dev/ttyUSB0", "model": "7-port Managed USB Hub",
# "serial": "00020000149E", "firmware": "v04", "n_ports": 7,
# "states": {"1": true, "2": true, "3": false, ...}}
# Make port 1 the only powered port and persist it
stuhubm all /dev/ttyUSB0 off
stuhubm on /dev/ttyUSB0 1
stuhubm save /dev/ttyUSB0
# Power-cycle a device on port 4 (off, wait, on)
stuhubm off /dev/ttyUSB0 4 && sleep 3 && stuhubm on /dev/ttyUSB0 4
Run any stuhubm command with --verbose to print the exact invocation.
Exit codes
Code |
Meaning |
|---|---|
|
Success |
|
Command failed (non-zero from the binary, parse error) |
|
Usage error (bad arguments) |
|
Binary not found |
|
Timeout |
Web GUI (stuhubm-gui)
Requires the [gui] extra.
stuhubm-gui # serves on http://localhost:8080
stuhubm-gui --port 9000 # custom port
stuhubm-gui --native # desktop window (requires pywebview)
The GUI provides hub discovery, a switch per port reflecting live state, all-on/all-off, save-to-flash, reset, restore, and a password-change dialog — plus a console pane showing the exact binary invocation and its output for every action. Settings (binary path, sudo, password, persist) are editable in-page. Each browser tab is independent, and a process-wide lock serialize the actual hardware calls so two tabs never issue overlapping commands.
The GUI is just a convenience layer; everything it does is also available through the CLI and the Python API.
Python API
The library mirrors the CLI. A short example:
from st_uhubm import HubManager, discover
# Convenience: discover with default settings (cusbi, sudo on)
for hub in discover():
print(hub.port, hub.model, hub.firmware, hub.states)
# Explicit configuration
mgr = HubManager(binary="cusba", use_sudo=False, password="s3cret")
hub = mgr.hub("/dev/ttyUSB0") # read one known hub
hub.set_port(3, on=False) # volatile by default
hub.set_port(3, on=True, persist=True) # write straight to flash
hub.set_all(on=False)
hub.toggle(2)
hub.save() # commit current states to flash
hub.refresh() # re-read live state
print(hub.is_on(3))
The parsers are also importable for custom integrations or for testing the tricky logic without hardware:
from st_uhubm.cli_backend import parse_query_all, parse_hub_info
parse_query_all("0002,/dev/ttyUSB0,/dev/ttyUSB1")
parse_hub_info("FBFFFFFF,7,v04,00020000149E,7-port Managed USB Hub")
The port-state bitmap is 32 bits, little-endian by byte; bit n−1 corresponds
to port n (1 = on).
Further details: every class, method, parser, and exception are in the API reference, generated directly from the source.
Configuration
Settings resolve in this order (later overrides earlier):
Built-in defaults
Environment variables (
STUHUBM_BINARY,STUHUBM_SUDO,STUHUBM_PASSWORD,STUHUBM_PERSIST)Command-line flags (CLI) or
HubManagerarguments (API)
This makes CI configuration straightforward: set the environment once, then call plain commands.
Use in CI automation
Typical pattern: power-cycle a DUT between stages:
# Example CI step (any runner with the hub attached)
env:
STUHUBM_BINARY: /opt/startech/cusbi
STUHUBM_SUDO: "1"
steps:
- run: stuhubm health
- run: stuhubm off /dev/ttyUSB0 4 # cut power to the DUT
- run: sleep 3
- run: stuhubm on /dev/ttyUSB0 4 # power back on
- run: stuhubm --json status /dev/ttyUSB0 # record final state
For unattended use, configure passwordless sudo scoped to the binary so calls
never block on a prompt (see below), or run the job as root.
Because the parsing functions are pure text processing, user can cover the tricky logic in their own unit tests without any hardware attached:
from st_uhubm.cli_backend import parse_hub_info
def test_port3_off():
n, states, fw, serial, model = parse_hub_info(
"FBFFFFFF,7,v04,00020000149E,7-port Managed USB Hub")
assert states[3] is False
assert n == 7
Troubleshooting
Binary not found
stuhubm health reports the binary cannot be located. Confirm the file is on
PATH or pass --binary /full/path/to/cusbi. On ARM hosts, ensure you are
using cusba, not cusbi.
No hubs detected
Check the cable :)
Confirm the device node exists:
ls /dev/ttyUSB*.Make sure the hub is externally powered if your model/setup requires it.
Try
stuhubm --verbose listto see the raw discovery output.
Permission denied / sudo prompts
The binary needs root to open the control tty.
Running without root
To avoid sudo entirely, grant your user access to the control device with a
udev rule. Identify the device’s vendor/product, then add (example):
# /etc/udev/rules.d/99-startech-hub.rules
SUBSYSTEM=="tty", ATTRS{idVendor}=="XXXX", ATTRS{idProduct}=="YYYY", MODE="0660", GROUP="dialout"
Reload rules (sudo udevadm control --reload && sudo udevadm trigger), add your
user to the dialout group, re-login, and run with --no-sudo.
Alternatively, allow passwordless sudo for just the binary in
/etc/sudoers.d/:
youruser ALL=(root) NOPASSWD: /usr/local/bin/cusbi
A port powers back on by itself
Some kernel drivers re-initialize a device shortly after a state change. If a
port you turned off comes back, persist the desired state (--persist or
stuhubm save) so the hub re-applies it, and verify with stuhubm status.
Forgotten password
If you set a password and lost it, use the physical recovery procedure in the
StarTech hardware manual (power off, hold the button, power on) to restore
factory defaults, which resets the password to pass.
Caveats
Flash wear.
--persist(the/Fpath) writes flash on every change. For frequently-toggled test rigs, make changes volatile andsaveonce.Power-cycling live devices. Cutting a port drops the device immediately. Ensure nothing is mid-write (e.g. mass storage) before switching a port off.
Root. The binary runs with elevated privileges; review the
--verboseoutput if you need to audit exactly what is executed.Compatibility. This package targets firmware v04+ output of the StarTech binary. If StarTech changes the binary’s output format in a future revision, parsing may need updating;
stuhubm --verboseand the exposed parser functions make this easy to diagnose.
Support
The public API is everything exported from the top-level st_uhubm package;
internal module layout may change between minor versions.
This is community software provided as-is. For issues with the hub hardware or the StarTech binary itself, contact StarTech support. Those are outside the scope of this package.
License
This package is released under the GNU General Public License, version 2 or
later (GPL-2.0-or-later). See the LICENSE file for the version 2 text.
It does not include or redistribute any StarTech software; the cusbi /
cusba binary is the property of StarTech.com and is governed by StarTech’s
own license terms. The GPL applies only to this project’s own code.