Skip to main content

Device discovery over Serial, USB, and TCP/IP

Project description

Dafydd

CI PyPI License Python Rust

Find your device, even when it isn't where it's supposed to be.

Dafydd is a Rust library with Python bindings (via PyO3) for two questions every embedded / instrument-control codebase asks:

  1. "I have a device of type X with serial number Y — where is it?" Sweep the relevant bus (USB / Serial / TCP), probe each endpoint, and return the one whose response matches your identifier.

  2. "My device was supposed to be at COM3 / VID:PID 1234:5678 / 192.168.1.50:5025. It's not. Find it anywhere else on the same bus." Try the expected location first with a short timeout. On failure, fall back to a probe-and-identify sweep — and return the actual location.

Same DeviceMatch shape comes back regardless of transport, so that it stays uniform across USB, Serial, and TCP devices.

Installation

pip install dafydd

Build from source (requires Rust 1.95+):

uv sync
uv run maturin develop --release

Use case 1 — "find this device, I don't know where it is"

You know the type (USB VID/PID, or how it responds to *IDN?). dafydd sweeps and returns the match.

Serial

import dafydd

# Find a device that responds to *IDN? with "MyDevice" anywhere on the bus.
matches = dafydd.SerialDiscovery(
    probe_command=b"*IDN?\r\n",
    baud_rates=[9600, 115200],
    timeout_ms=500,
    response_filter=b"MyDevice",
    response_terminator=b"\r\n",
).discover()

for m in matches:
    print(f"{m.address} @ {m.baud_rate} baud: {m.response}")

USB

# Filter by vendor/product ID — descriptor enumeration only, no probing.
matches = dafydd.UsbDiscovery(vid=0x04D8, pid=0x000A).discover()
for m in matches:
    print(f"{m.address}  {m.info.get('product', '')}")

TCP

# Sweep the LAN for a device that answers to your probe with the right ID.
matches = dafydd.TcpDiscovery(
    port=5025,
    probe_command=b"*IDN?\n",
    response_filter=b"SN:ES123DFD3",
).discover()

for m in matches:
    print(m.address, m.info.get("mac"))   # info["mac"] populated when from ARP

Use case 2 — "it should be at X but it isn't; find it"

You have an expected location. Try it first; on failure, fall back to a full bus sweep filtered by probe response.

Serial — "should be COM3, but COM3 is empty"

m = dafydd.SerialDiscovery(
    probe_command=b"C0AMSF\r\n",
    response_filter=b"sn:ES123DFD3",
    preferred_port="COM3",          # try this first with a fast timeout
    preferred_retry=2,              # retry a couple of times
    baud_rates=[9600],
    timeout_ms=200,
).discover()
# m[0].address now points to wherever the device actually is — COM4, /dev/ttyUSB1, …

TCP — "should be 192.168.1.50:5025, but it's not"

m = dafydd.TcpDiscovery(
    port=5025,
    preferred_host="192.168.1.50",  # try first; if no response, sweep
    probe_command=b"*IDN?\n",
    response_filter=b"SN:ES123DFD3",
    subnet_prefix=24,               # how broad the fallback sweep goes
).discover()

Passing the result to your transport library

Every DeviceMatch produces kwargs ready for python-bus (or any serial/socket library) via .bus_params():

import bus  # python-bus

match = matches[0]
device = bus.Device(**match.bus_params())
device.write(b"some-command")

Streaming and Watch

import dafydd

token = dafydd.CancellationToken()

# Streaming — callback fires as each device is found.
dafydd.SerialDiscovery(
    probe_command=b"*IDN?\r\n",
    baud_rates=[9600],
    timeout_ms=500,
    cancellation_token=token,
).discover_streaming(lambda d: print("found", d.address))

# Watch — fires on plug/unplug. USB uses real OS hotplug; Serial and TCP poll.
import threading
threading.Thread(
    target=dafydd.UsbDiscovery(vid=0x04D8).watch,
    kwargs={
        "on_added":   lambda d: print("connected",    d.address),
        "on_removed": lambda d: print("disconnected", d.address),
    },
    daemon=True,
).start()

# Stop from any thread.
token.cancel()

Configuration knobs

TcpDiscovery

Knob Default Purpose
subnet_prefix 24 Broadest auto-detected subnet to sweep. Must be in [16, 32]. 16 allows /16 sweeps (65 k hosts, slow); 24 is the polite default.
tcp_linger_seconds None TCP SO_LINGER. None = OS default (graceful FIN close). 0 = RST close, no TIME_WAIT — fast but antisocial; use only on networks you own. n>0 = block for n seconds.
use_arp_cache True Probe IPs from the kernel ARP cache before the linear sweep. Pure-Rust on all platforms (no arp subprocess). When a match comes from ARP, its info["mac"] is populated.
use_mdns / use_ssdp False Active DNS-SD or SSDP M-SEARCH before the sweep. Useful for routers, cameras, printers.
preferred_host, preferred_retry None / 0 "Try here first" fast-path.

SerialDiscovery

Key knobs: preferred_port, probe_command, response_filter, response_terminator, baud_rates, port_filter (callback to exclude ports), include_bluetooth (Windows). See the docstring on the class for the full list.

UsbDiscovery

Filters: vid, pid, manufacturer, product, serial, class. All optional. Real OS hotplug via nusb::watch_devices().

Utilities

# Auto-detect local subnets — same list TcpDiscovery uses when `subnets=[]`.
print(dafydd.local_subnets())              # default /24 ceiling
print(dafydd.local_subnets(max_prefix=20)) # allow up to /20 (4096 hosts)

How it works

  1. Preferred-address path (when configured): try the named port / host / VID:PID with a short timeout. On success, return immediately.
  2. TCP only — priority probes: ARP cache (with MAC stamped on the match), then common last-octet heuristics (.1, .100, .254, …), then optional mDNS/SSDP responders.
  3. Full sweep: enumerate endpoints, probe concurrently via Tokio JoinSet + semaphore. With raw-socket privilege on Linux, a single-RTT SYN scan further narrows TCP targets to open ports.
  4. macOS tty dedup (Serial): the blocking /dev/tty.* variant of each port is filtered out so probes use /dev/cu.*.

Building from source

# Editable install
uv sync
uv run maturin develop

# Release build
uv run maturin develop --release

# Rust-only tests + benches
cargo test
cargo bench --bench tcp_scan       # see benches/README.md

Contributing

See CONTRIBUTING.md.

License

MIT — see LICENSE.

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

dafydd-0.1.2.tar.gz (82.5 kB view details)

Uploaded Source

Built Distributions

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

dafydd-0.1.2-cp313-cp313-win_amd64.whl (661.5 kB view details)

Uploaded CPython 3.13Windows x86-64

dafydd-0.1.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (1.1 MB view details)

Uploaded CPython 3.13manylinux: glibc 2.17+ x86-64

dafydd-0.1.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (1.1 MB view details)

Uploaded CPython 3.13manylinux: glibc 2.17+ ARM64

dafydd-0.1.2-cp313-cp313-macosx_11_0_arm64.whl (614.2 kB view details)

Uploaded CPython 3.13macOS 11.0+ ARM64

dafydd-0.1.2-cp312-cp312-win_amd64.whl (661.4 kB view details)

Uploaded CPython 3.12Windows x86-64

dafydd-0.1.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (1.1 MB view details)

Uploaded CPython 3.12manylinux: glibc 2.17+ x86-64

dafydd-0.1.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (1.1 MB view details)

Uploaded CPython 3.12manylinux: glibc 2.17+ ARM64

dafydd-0.1.2-cp312-cp312-macosx_11_0_arm64.whl (614.3 kB view details)

Uploaded CPython 3.12macOS 11.0+ ARM64

dafydd-0.1.2-cp311-cp311-win_amd64.whl (663.1 kB view details)

Uploaded CPython 3.11Windows x86-64

dafydd-0.1.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (1.1 MB view details)

Uploaded CPython 3.11manylinux: glibc 2.17+ x86-64

dafydd-0.1.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (1.1 MB view details)

Uploaded CPython 3.11manylinux: glibc 2.17+ ARM64

dafydd-0.1.2-cp311-cp311-macosx_11_0_arm64.whl (615.1 kB view details)

Uploaded CPython 3.11macOS 11.0+ ARM64

File details

Details for the file dafydd-0.1.2.tar.gz.

File metadata

  • Download URL: dafydd-0.1.2.tar.gz
  • Upload date:
  • Size: 82.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for dafydd-0.1.2.tar.gz
Algorithm Hash digest
SHA256 7f16d1393c1686a1b35f8ef63f511fce9de9d2b57d0fd429ae334654035d577a
MD5 b64920905d25e3532786f01f6b6c373d
BLAKE2b-256 7b027fd82eeabd7cbd9841d11fdaf3a220bf6f066a0e1d051361bd90b597d79d

See more details on using hashes here.

Provenance

The following attestation bundles were made for dafydd-0.1.2.tar.gz:

Publisher: release.yml on tstenvold/dafydd

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file dafydd-0.1.2-cp313-cp313-win_amd64.whl.

File metadata

  • Download URL: dafydd-0.1.2-cp313-cp313-win_amd64.whl
  • Upload date:
  • Size: 661.5 kB
  • Tags: CPython 3.13, Windows x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for dafydd-0.1.2-cp313-cp313-win_amd64.whl
Algorithm Hash digest
SHA256 4ff365dc5484936fdd541baf8b81591e737b1850773d7d33ae1e4186f9e0e49e
MD5 a64dcedd453160ec1342538a1584cb73
BLAKE2b-256 fb072f4e840557e7a9b7d56c1da7b57fc5b260f6d083d3d874805db35abf8589

See more details on using hashes here.

Provenance

The following attestation bundles were made for dafydd-0.1.2-cp313-cp313-win_amd64.whl:

Publisher: release.yml on tstenvold/dafydd

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file dafydd-0.1.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for dafydd-0.1.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 c94d425e8e43180a82fd658606cd40a4e5e8643085b65c55cd9cf997ed13d419
MD5 9a33fe9ae4dae1bb5600ea5f18185e7e
BLAKE2b-256 9c78fe6f5e80a42bfbc14dd5e00757aec9f87fbcd2bb41676bfe35284a40d959

See more details on using hashes here.

Provenance

The following attestation bundles were made for dafydd-0.1.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl:

Publisher: release.yml on tstenvold/dafydd

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file dafydd-0.1.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for dafydd-0.1.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 6fcb056058045b95662e5150687ca5c024d338e6215546a4d62cab97889d9237
MD5 33da6d785bf78076744a94ada3fe0d9b
BLAKE2b-256 7d2af777c32bf60c3511c371de0d78e6e6d62c556008468de8550a948e9c5346

See more details on using hashes here.

Provenance

The following attestation bundles were made for dafydd-0.1.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl:

Publisher: release.yml on tstenvold/dafydd

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file dafydd-0.1.2-cp313-cp313-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for dafydd-0.1.2-cp313-cp313-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 f164995e02d38d269d00c09930b6c9d899d881bcd986f09134a4318778552dc4
MD5 2780154efb2f09a280c69350db7b4f05
BLAKE2b-256 1e45e01308218745c6a69b6eeb2b9eb250b91b856c10880b883e8547794f135e

See more details on using hashes here.

Provenance

The following attestation bundles were made for dafydd-0.1.2-cp313-cp313-macosx_11_0_arm64.whl:

Publisher: release.yml on tstenvold/dafydd

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file dafydd-0.1.2-cp312-cp312-win_amd64.whl.

File metadata

  • Download URL: dafydd-0.1.2-cp312-cp312-win_amd64.whl
  • Upload date:
  • Size: 661.4 kB
  • Tags: CPython 3.12, Windows x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for dafydd-0.1.2-cp312-cp312-win_amd64.whl
Algorithm Hash digest
SHA256 c0f34ce2e793614bf3cc9d0e2ceaedfcd9d55b22fab768a4def32c1a453f16c8
MD5 3b4f2fc431a53300b42fd945b3079f1b
BLAKE2b-256 f09637256ca2caae385e144e15899cbbb86328ba33c794dda77f414c62165d9e

See more details on using hashes here.

Provenance

The following attestation bundles were made for dafydd-0.1.2-cp312-cp312-win_amd64.whl:

Publisher: release.yml on tstenvold/dafydd

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file dafydd-0.1.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for dafydd-0.1.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 1d270baf603f15ea1607f3eec4fd991e0a092569ecea63180ca015708515d11c
MD5 86ecb96a75b90decfc05e2ef905caba6
BLAKE2b-256 c8c9f4bab0c40f6c96a7b6c2a10acf19105a51626c4c52f8b6ad702f9c5a1ca3

See more details on using hashes here.

Provenance

The following attestation bundles were made for dafydd-0.1.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl:

Publisher: release.yml on tstenvold/dafydd

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file dafydd-0.1.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for dafydd-0.1.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 06857c7436b0dedd1d2e2a38b9d895eff1bdb7458e2ef0f97fc1ac198bf0b3a2
MD5 7de2eb91efc18a1a0a2bd8e5b5438242
BLAKE2b-256 410c44f630428dba72d7561ae7b74cc12da22ca96e4ee8d192166776c547b55c

See more details on using hashes here.

Provenance

The following attestation bundles were made for dafydd-0.1.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl:

Publisher: release.yml on tstenvold/dafydd

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file dafydd-0.1.2-cp312-cp312-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for dafydd-0.1.2-cp312-cp312-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 d7686defe48b6c1621ede3cf8ce72632e8dea20e196593b9c6e711e644b739b1
MD5 49404b12641e64d936226b005def8751
BLAKE2b-256 61d2855258c38de877d735da18f26d73b348775baf75cd3eb8ee63741542a114

See more details on using hashes here.

Provenance

The following attestation bundles were made for dafydd-0.1.2-cp312-cp312-macosx_11_0_arm64.whl:

Publisher: release.yml on tstenvold/dafydd

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file dafydd-0.1.2-cp311-cp311-win_amd64.whl.

File metadata

  • Download URL: dafydd-0.1.2-cp311-cp311-win_amd64.whl
  • Upload date:
  • Size: 663.1 kB
  • Tags: CPython 3.11, Windows x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for dafydd-0.1.2-cp311-cp311-win_amd64.whl
Algorithm Hash digest
SHA256 ec80b823fbe47d8a5878f7d84a3e87e1fa38d771e3435272d350136df93b4458
MD5 982dd6fcddc4f93411c67ddb1a7c0f23
BLAKE2b-256 757889d65b41de21dd4962d1256eca0341bec4318415777a3070903676b4022d

See more details on using hashes here.

Provenance

The following attestation bundles were made for dafydd-0.1.2-cp311-cp311-win_amd64.whl:

Publisher: release.yml on tstenvold/dafydd

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file dafydd-0.1.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for dafydd-0.1.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 ff8767f3a8e7353a06fdb9ab8d084d4848fe9751d6a903a1f97730d8ec51f0e8
MD5 403c3ede3388605f84e77ecc5529ca9b
BLAKE2b-256 5b8631896e3b062f2907bfe61368acd9d166a39ce14e1323df54048a1a6b0d36

See more details on using hashes here.

Provenance

The following attestation bundles were made for dafydd-0.1.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl:

Publisher: release.yml on tstenvold/dafydd

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file dafydd-0.1.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for dafydd-0.1.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 b767c60d7740928906ec3711edc1d82c8822d7c84ba8804a29840baf144abae6
MD5 ca7e0e6360685f0571efddc20359ec74
BLAKE2b-256 92c5e7b7495c8feead5add8c169d9fc005ec506c3741d03d94856c81efa88172

See more details on using hashes here.

Provenance

The following attestation bundles were made for dafydd-0.1.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl:

Publisher: release.yml on tstenvold/dafydd

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file dafydd-0.1.2-cp311-cp311-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for dafydd-0.1.2-cp311-cp311-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 a05e8d463b2c73c6e534a8bf5488b98ad4033b738c2869f987d958e50f9627e1
MD5 7734a47c8a3239cb2aca6848216459bd
BLAKE2b-256 f93644c897e420e95e8b08b2e739f326a7ecb90a6675b2396506d3931fe75751

See more details on using hashes here.

Provenance

The following attestation bundles were made for dafydd-0.1.2-cp311-cp311-macosx_11_0_arm64.whl:

Publisher: release.yml on tstenvold/dafydd

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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