feat(pm3py): auto-detect proxmark3 port when none specified

This commit is contained in:
michael
2026-03-16 00:10:50 -07:00
parent 205e9b7993
commit 29bfccfb41

View File

@@ -1,7 +1,9 @@
"""Main Proxmark3 client with nested API."""
import asyncio
import glob
import inspect
import logging
import sys
from dataclasses import dataclass, field
from .transport import PM3Transport, PM3Response, PM3Error, ProgressCallback
@@ -26,21 +28,42 @@ class FirmwareInfo:
warnings: list[str] = field(default_factory=list)
def find_proxmark_port() -> str | None:
"""Auto-detect the first available Proxmark3 serial port."""
if sys.platform == "darwin":
patterns = ["/dev/tty.usbmodem*"]
elif sys.platform == "win32":
# On Windows, we can't glob — caller should specify port
return None
else:
patterns = ["/dev/ttyACM*", "/dev/ttyUSB*"]
for pattern in patterns:
ports = sorted(glob.glob(pattern))
if ports:
return ports[0]
return None
class Proxmark3:
"""Proxmark3 device client with structured Python API.
Usage:
async with Proxmark3("/dev/ttyACM0") as pm3:
if not pm3.firmware.compatible:
print("Warnings:", pm3.firmware.warnings)
status = await pm3.hw.version()
print(status)
async with Proxmark3() as pm3: # auto-detect port
print(await pm3.hw.ping())
# Raw access:
async with Proxmark3("/dev/ttyACM0") as pm3: # explicit port
resp = await pm3.send_ng(0x0108)
pm3 = Proxmark3.sync() # sync REPL, auto-detect
"""
def __init__(self, port: str, baudrate: int = 115200):
def __init__(self, port: str | None = None, baudrate: int = 115200):
if port is None:
port = find_proxmark_port()
if port is None:
raise PM3Error("No Proxmark3 device found")
log.info("pm3py: auto-detected %s", port)
self._transport = PM3Transport(port, baudrate)
self.hw = HWCommands(self._transport)
self.lf = LFCommands(self._transport)
@@ -106,14 +129,14 @@ class Proxmark3:
return await self._transport.send_mix(cmd, arg0, arg1, arg2, payload, timeout)
@classmethod
def sync(cls, port: str, baudrate: int = 115200) -> "Proxmark3":
def sync(cls, port: str | None = None, baudrate: int = 115200) -> "Proxmark3":
"""Create a synchronous client for REPL / script usage.
Usage:
pm3 = Proxmark3.sync("/dev/ttyACM0")
pm3 = Proxmark3.sync() # auto-detect
pm3 = Proxmark3.sync("/dev/ttyACM0") # explicit
print(pm3.firmware)
print(pm3.hw.ping())
print(pm3.hf.mf.rdbl(block=0))
pm3.close()
"""
instance = cls(port, baudrate)