Skip to main content

Small toolkit for automating a serial-attached Linux shell

Project description

sdev

Small toolkit for automating a serial-attached Linux shell.

Installation

pip install -e .

CLI

# Run a command
sdev -p "ls /proc/meminfo" -d /dev/ttyUSB0 -b 115200

# Stream output incrementally
sdev -p "tail -f /var/log/syslog" --stream

# Stream with server-side regex filter
sdev -p "tail -f /var/log/syslog" --stream --grep "ERROR"

# Stream with complete-line output only
sdev -p "dmesg" --stream --line-mode

# Parse output with regex
sdev -p "cat /proc/meminfo" --parse "Mem.*"

# Wait for a specific output marker instead of shell prompt
sdev -p "./mnn_perf -m model.mnn" --end-flag "Frame rate:"

# Clear stray processes before running a command
sdev -p "uptime" --doctor

# Save defaults so you can omit -d and -b
sdev set-default /dev/ttyUSB0 115200
sdev -p "ls /proc/meminfo"

# Send Ctrl+C to interrupt a running command (without -p)
sdev --interrupt -d /dev/ttyUSB0 -b 115200

# Detect serial boards on this system
sdev --probe
sdev --probe --probe-baud 9600 --probe-baud 38400

# Custom prompt patterns for non-standard shells
sdev -p "ls" --prompt "[root@board]# " --prompt "admin@box> "

CLI options

Flag Description
-p, --command Command to execute
-d, --device Serial device path
-b, --baud Baud rate
-t, --timeout Timeout in seconds (default: 300)
--stream Incremental output instead of buffered
--grep REGEX Filter --stream lines by regex
--line-mode Only yield complete lines in --stream
--parse REGEX Show only matching lines
--end-flag STR Stop when this string appears in output
--doctor Clear foreground processes before command
--prompt PATTERN Custom shell prompt pattern (repeatable)
--interrupt Send Ctrl+C and wait for prompt
--probe Detect serial boards and print info
--probe-baud BAUD Baud rates to try during --probe (repeatable)
set-default Persist device/baud as defaults

Design Goals

  • Stability: strict 5-minute timeout on all blocking operations
  • Simplicity: small surface area, obvious API
  • Predictability: prompt detection to determine command completion
  • Streaming: incremental output for long-running commands
  • Parsing: structured output with optional regex filtering

Python API

import sdev

# Session-based (recommended)
with sdev.SerialSession("/dev/ttyUSB0", 115200) as session:
    result = session.cli("ls /proc/meminfo")
    print(result.output)

# Custom prompt detection for non-standard shells
session = sdev.SerialSession("/dev/ttyUSB0", 115200, prompts=[b"[root@board]# "])
session.connect()

# Streaming for long-running commands
for chunk in session.stream("tail -f /var/log/syslog"):
    print(chunk, end="")

# Streaming with line mode — only yields complete lines
for line in session.stream("tail -f /var/log/syslog", line_mode=True):
    process(line)

# Streaming with server-side filter
for chunk in session.stream("tail -f /var/log/syslog", filter_fn=lambda t: t.upper()):
    print(chunk, end="")

# Parsing with regex filtering
parsed = session.parse("cat /proc/meminfo", pattern=r"Mem.*")
print(parsed.matched)

# Wait for a specific output marker instead of shell prompt
# Useful for benchmarks that print results then keep running
result = session.cli("./mnn_perf -m model.mnn", end_flag="Frame rate:")

# Interrupt a running command (sends Ctrl+C and waits for prompt)
session.interrupt(timeout=5)

# Clear stray foreground processes and get a clean prompt
session.doctor()

# Wait until no data arrives for N seconds (boot completion)
session.wait_for_silence(timeout=1.5)

# Recover from device reboot without creating a new session
session.reconnect()

# Monitor CPU/memory during long operations
usage = sdev.resource_usage()
print(f"RSS: {usage['memory_mb']} MB, CPU: {usage['cpu_percent']}%")

# Detect serial boards and get OS/arch info
for device in sdev.probe():
    print(f"{device['device']} @ {device['baud']}: {device['info']['os_name']}")

# Send raw bytes over serial (control sequences, custom protocols)
sdev.connect("/dev/ttyUSB0", 115200)
n = sdev.write(b"reboot\n")
print(f"Wrote {n} bytes")

# Clear stray foreground processes on the default connection
sdev.doctor()

# Wait for boot completion (no serial data for N seconds)
sdev.wait_for_silence(timeout=2.0)

Thread safety

Each SerialSession has an internal threading.Lock. Only one cli() or stream() call can run at a time per session. Concurrent callers will raise RuntimeError after 10s if the lock is held. interrupt() does not acquire the lock — it remains the emergency escape hatch.

Module-level convenience API

sdev.connect("/dev/ttyUSB0", 115200)
result = sdev.cli("ls /proc/meminfo")
sdev.disconnect()

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

sdev-1.0.0.tar.gz (37.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

sdev-1.0.0-py3-none-any.whl (14.1 kB view details)

Uploaded Python 3

File details

Details for the file sdev-1.0.0.tar.gz.

File metadata

  • Download URL: sdev-1.0.0.tar.gz
  • Upload date:
  • Size: 37.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.10

File hashes

Hashes for sdev-1.0.0.tar.gz
Algorithm Hash digest
SHA256 5a4ed7aa7e89fbc1deafdbc44ea51d6c9d052fb85a86847ae0781a553a2e8589
MD5 c2859c9fc88c27a0b15a69172e3fb768
BLAKE2b-256 ee4e1f4134b5c003202d90b16c4ac8ef8935c8207def857577aeb94697ae5020

See more details on using hashes here.

File details

Details for the file sdev-1.0.0-py3-none-any.whl.

File metadata

  • Download URL: sdev-1.0.0-py3-none-any.whl
  • Upload date:
  • Size: 14.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.10

File hashes

Hashes for sdev-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 4868d555efa89ba242154205c8fe9917860f63d7e46202773fc70b237d16260b
MD5 6dad867438dcf0475a24ac7fc4445c9e
BLAKE2b-256 7e28663106b4d5e9fdfd75bee9dff9c226b2e154b71725361655a5dcde93b51f

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page