TurboSSH — SSH / Serial / SFTP / FTP terminal & automation toolkit for automotive & embedded (API, CLI, and a MobaXterm-style PyQt5 GUI).
Project description
TurboSSH
TurboSSH is an SSH / Serial / SFTP / SCP / FTP / RDP terminal and automation toolkit built on Paramiko — for automotive & embedded work, test automation, and everyday remote ops. It ships three ways in one install:
- Python API —
import turbossh(orssh_handler) for scripts & test frameworks. - CLI —
turbossh …, fully argument-driven. - MobaXterm-style GUI —
turbossh-gui, a tabbed multi-session terminal with a true VT100 emulator (htop/vim/top work), an SFTP browser, serial consoles, and RDP launch. Ships as a prebuilt Windows exe (PyQt5 baked in — no PyQt5 install needed).
pip install turbossh
turbossh-gui
Table of contents
- Install
- The GUI
- Quick start (API)
- Connecting — local & via RDP jump
- Running commands
- Continuous logs (slog2info / journalctl / tail -f)
- File transfer — SFTP / SCP / FTP
- Serial / COM ports
- Automotive / legacy devices
- Confidential credentials
- Enable SSH on a Windows/RDP box (offline)
- CLI reference
- Result objects & error handling
- Embed in your own PyQt5 app
- Building the exe
- API map
Install
pip install turbossh # API + CLI + prebuilt Windows GUI exe
pip install "turbossh[gui]" # also installs PyQt5 to run the GUI from source
Batteries included: paramiko, scp, pyserial, keyring, pywinrm, and
pyte (VT100) are pulled in automatically. Only PyQt5 is optional — the shipped
GUI exe already contains it, so turbossh-gui works without installing PyQt5
(handy on Windows ARM64, where PyQt5 has no wheel).
The GUI (MobaXterm-style)
turbossh-gui
- Session manager sidebar — saved SSH / Serial / RDP sessions. Passwords are kept in the OS credential vault, never in the JSON. New / Edit / Delete / Connect.
- Tabbed sessions — many connections open at once, each a closable tab.
- True VT100 terminal (pyte) — full-screen apps like htop, vim, top, less, nano render correctly, with colors, a block cursor, and live PTY resize.
- Quick buttons — one-click
slog2info -w,journalctl -f,dmesg -w,tail -f, plus Ctrl-C and Clear. - Split SFTP browser under each SSH terminal — navigate, upload, download, mkdir, rename, delete (transfers on a separate channel; UI never blocks).
- Serial console — open a COM port and type/read live.
- RDP session — launches native Remote Desktop (
mstsc) with credentials pre-seeded. - Keyboard shortcuts — Ctrl+T/N new session, Ctrl+W close tab, Ctrl+Enter connect, F1 docs; in the terminal: Ctrl+Shift+C/V copy-paste, Ctrl-C/D/Z, arrows, Tab-completion (server-side), function keys.
- Crash-proof — background threads for all I/O; a startup failure shows a
native popup and writes
~/.ssh-handler/crash.log; runtime errors are logged, never fatal.
Quick start (API)
from turbossh import SSHHandler, SSHConfig
with SSHHandler(SSHConfig(host="10.0.0.5", username="root", password="pw")) as ssh:
print(ssh.run("uname -a").text) # clean single-line output
ssh.run("systemctl restart nginx", check=True)
ssh.push("local.txt", "/tmp/remote.txt")
ssh.pull("/etc/nginx", "./backup", recursive=True)
Connecting — local & via RDP jump host
The same methods work everywhere; only the config changes.
# direct
cfg = SSHConfig(host="10.0.0.5", username="root", password="pw",
host_key_policy="ignore") # ignore = lab/reimaged devices
# through an RDP/bastion machine (laptop -> jump -> target)
jump = SSHConfig(host="10.232.9.22", domain="CORP", username="user", password="pw")
cfg = SSHConfig(host="10.120.1.91", username="root", password="pw",
jump_host=jump, host_key_policy="ignore")
with SSHHandler(cfg, quiet=True) as ssh:
print(ssh.run("hostname").text)
host_key_policy |
Behaviour |
|---|---|
"auto" (default) |
add unknown keys, reject changed keys |
"ignore" |
accept any key incl. changed — for reimaged/DHCP lab devices |
"reject" |
strict; only keys already in known_hosts |
Running commands
r = ssh.run("ls -la", timeout=30, check=False)
print(r.text) # stdout, stripped print(r.stdout) # raw
print(r.exit_code, r.ok, r.duration)
ssh.run_many(["a", "b", "c"], stop_on_error=True)
ssh.sudo("systemctl restart app", password="pw")
Continuous logs
# stream live, match a pattern, tee to a file (ANSI auto-cleaned)
ssh.stream("slog2info -w", on_line=print,
match=r"error|fail", save_to="device.log", timeout=120)
# generator form
for line in ssh.iter_lines("journalctl -f"):
print(line)
match is a regex; stop_on_match=True stops at the first hit (send/expect).
File transfer — SFTP / SCP / FTP
ssh.push("fw.bin", "/tmp/fw.bin") # SFTP upload
ssh.pull("/var/log/messages", "messages.log") # SFTP download
ssh.push("./build", "/tmp/build", recursive=True) # folder, with progress callback
ssh.scp_push("img.tar", "/tmp/img.tar") # SCP protocol
from turbossh import FTPHandler, FTPConfig
with FTPHandler(FTPConfig(host="ftp.x", username="u", password="p", use_tls=True)) as ftp:
ftp.push("a.txt", "a.txt"); ftp.pull("b.txt", "b.txt")
Via RDP: identical — transfers ride the jump_host tunnel automatically. Remote
FS helpers: listdir, stat, exists, isdir, mkdir, makedirs, rename, remove, chmod,
read_text, write_text, walk.
Serial / COM ports
# local port (device plugged into THIS machine)
from turbossh import SerialHandler, list_serial_ports
print(list_serial_ports())
with SerialHandler("COM5", baudrate=115200) as ser:
ser.write_line("version")
ser.stream(on_line=print, match=r"login:", save_to="com5.log")
# port on a REMOTE machine, over SSH/jump (COM = Windows, /dev/tty* = Linux)
with SSHHandler(cfg, quiet=True) as ssh:
ssh.serial_write("COM5", "version", baudrate=115200)
ssh.serial_stream("COM5", baudrate=115200, on_line=print,
match=r"login:", save_to="com5.log")
Automotive / legacy devices
Old ECUs / embedded SSH servers often use crypto modern Paramiko drops. Re-enable it:
cfg = SSHConfig(host="10.0.0.9", username="root", password="pw",
enable_legacy_algorithms=True) # old KEX/ciphers/host-keys
# fine-grained: disabled_algorithms={"pubkeys": ["rsa-sha2-512"]}
In the GUI, tick "Enable legacy algorithms" in the session dialog.
Confidential credentials
| Mechanism | What it does |
|---|---|
Secret |
wraps a password; logs/reprs show ********; only .reveal() exposes it |
mask() |
redacts secrets from any string (applied to all logging automatically) |
CredentialStore |
stores/reads passwords in the OS vault via keyring — no plaintext |
prompt_password() |
hidden terminal input |
Enable SSH on a Windows/RDP box (offline)
turbossh-setup # self-elevates, installs OpenSSH Server from a bundled
# ZIP (ARM64/Win64/Win32), starts sshd, opens firewall,
# generates + fixes host keys. No internet/Windows Update.
Or auto-enable a remote box over WinRM: SSHConfig(auto_bootstrap_via_winrm=True).
CLI reference
turbossh run --host H --user U [--domain CORP] [--use-stored] uname -a
turbossh push --host H --user U ./build /tmp/build --recursive
turbossh pull --host H --user U /var/log ./logs --recursive
turbossh info --host H --user U --json
turbossh store-credential --user U --domain CORP --service my_lab
turbossh-gui # launch the GUI
turbossh-setup # install OpenSSH Server on this machine (offline)
turbossh-shortcut # create a Desktop shortcut to the GUI
turbossh-docs # open the docs
Password options: --password (hidden prompt), --use-stored (OS vault), --key FILE.
Result objects & error handling
CommandResult—.exit_code,.stdout,.text,.stderr,.duration,.okTransferResult—.size_bytes,.duration,.human_speed,.filesOperationResult— safe-mode wrapper:bool(res),.value,.error,.unwrap()
Raise mode (default): typed exceptions — SSHConnectionError,
SSHAuthenticationError, SSHTimeoutError, SSHCommandError, SSHTransferError,
FTPError, SerialError, WinRMError, CredentialError (all subclass SSHError).
Auto-retry on connect + auto-reconnect on drop are built in, and a failed connect
self-diagnoses (probes SSH/RDP ports and explains why).
Safe mode (SSHHandler(cfg, safe=True)): every call returns an
OperationResult instead of raising — ideal for GUIs/long-running tools.
Embed in your own PyQt5 app
ssh_handler.pyqt_worker.SSHWorker is a QObject (safe mode) you move to a
QThread and drive via signals (log, connected, command_done,
transfer_done, progress, error, finished).
Building the exe
pip install "turbossh[gui]" pyinstaller
python scripts/build_exe.py # dist/turbossh-gui/...
python scripts/build_exe.py --onefile # single .exe
API map
turbossh/ import shim -> re-exports ssh_handler
ssh_handler/
config.py SSHConfig (legacy algos, jump, host-key policy…), FTPConfig
core.py SSHHandler (SSH + SFTP + SCP + stream + serial + diagnose)
serial_handler.py SerialHandler, list_serial_ports
ftp.py FTPHandler (FTP/FTPS)
winrm_bootstrap.py enable_openssh_via_winrm
pool.py SSHPool (parallel multi-host)
credentials.py Secret, CredentialStore, mask, prompt_password
results.py CommandResult, TransferResult, ShellResult, OperationResult
cli.py CLI + launchers (gui/docs/setup/shortcut/rdp)
pyqt_worker.py SSHWorker (embed in your own GUI)
bin/turbossh-gui.exe prebuilt GUI (PyQt5 baked in)
gui/ MobaXterm-style app
vt100.py true VT100 terminal (pyte) — htop/vim render correctly
terminal.py reader thread
sftp_browser.py remote file browser (threaded transfers)
session_dialog.py / sessions.py session manager + saved profiles
session_widgets.py SSH terminal + SFTP split, serial console
main_window.py · app.py · theme.py · log_panel.py
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distributions
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file turbossh-0.5.0-py3-none-any.whl.
File metadata
- Download URL: turbossh-0.5.0-py3-none-any.whl
- Upload date:
- Size: 64.4 MB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
cc6ae59e35e6743fab29bed0281e01312d7f0c7922390949aa69799290786db5
|
|
| MD5 |
446cb24c3fa306ec3ecc08576a2a2484
|
|
| BLAKE2b-256 |
7fdbf1cf5e3e740cabcc1535f460d1c33538ab8a8c81ef7b8e93b4be9ad14776
|