Module and tool to discover all boards connected to USB.
The discotool
command line program and the discotool
python module for python 3 can be installed with pip.
python3 -m pip install discotool
It currently runs on MacOS, Linux and Windows. It should not require any installation outside of pip dependencies (no libusb, etc.). If it doesn't work for you, an issue with relevant OS information is welcome.
When running discotool
while using a single board, it will be automatically selected for commands. These are the commands I use the most:
discotool repl
: to connect to the REPL.discotool install ...
: to install modules via circup.discotool update
: to update modules via circup.
I often have more than one board connected, and connect to the REPL using discotool -n pico
for example, or using the drive (mount) name to give each board a personnal name discotool -m picotwo
.
I also use a command to back up all connected boards.
alias cpbackups='discotool backup --date ~/Backups/CPBackups'
Define environment variables to override the default command line tools used by discotool. They are called by appending the relevant parameters at the end of the command, or replacing a placeholder.
DISCOTOOL_SERIALTOOL
: command to connect to the REPL (tio, picocom, etc.), adds the port at the end or replaces{port}
if present.- on windows
{portnum}
is the6
inCOM6
, required by TeraTerm. - default values, using the first one found:
- TeraTermPro, PuTTY on Windows.
- tio, screen on linux/mac.
- on windows
DISCOTOOL_CIRCUP
: (circup
) command to call circup (pip install
it for the default).DISCOTOOL_NOCOLOR
: disables colors in the output if it evaluates to True.
--wait
: runs the scan every second until it detects a board.--nocolor
: do not output colors in the terminal (overrides all else).--color
: output colors in the terminal (overrides all else).--info
: add more informations on Circuitpython boards by scanning the drive's content (might trigger the autoreload).
- if no filter is given, run the
list
command. - if filters are given, run the
repl
command.
Filters select boards from the list of devices found to run a command on them. They are combined with OR logic: anything that matches any filter is selected. All filters are NOT case sensitive. Filters are simple text matches, they don't support wildcards.
--auto
: select the first board found.--name
: search in the USB name/description field. Eg: "clue", "QT", "S2".--serial
: search the serial number of the board.--mount
: search the volume names of the board. Eg: "CIRCUITPY".
list
: lists the selected boards, with name, manufacturer, serial number. Lists the serial ports and file volumes. If the--info
option was given, identifies circuitpython code files present, as well as CPY version. On windows the name of the drive is listed in addition to the drive letter.repl
: connect to the REPL of the selected boards using the tool specified, screen by default, choosing the first serial port found if there is more than one.eject
: eject all selected board drives, or all found if no filter given. (MacOS only for now)backup <destination dir> [<sub dir>]
: copy the content of the selected boards drives into the destination dir or the optional sub dir (that will be created for you). Each board is put in a directory with its name and serial number.--create
: create the destination dir if it does not exist.--date
: use a time stamp as subdirectory name, or add to the supplied name.
circup <options>
: calls circup with its--path
option to each selected board and passes all other options and commands to it.get <key>
: print just the value for the key, for the selected devices. Can be used with backticks and such in a shell script. Includes special keys:pid
,vid
,sn
: shortcuts for product_id, vendor_id and serial_num.volume
: path to the (first) mounted drive of the device.port
: (first) serial port of the device.repl
: (first) REPL serial port of the device.cdc
: (first) non-REPL serial port of the device.main
orcode.py
: full path to the main file for circuitpython.
json
: print the output of usbinfo as json for all selected boards.--pretty
-p
: pretty print it for human reading.
Exposes the get_identified_devices(drive_info=False)
function. Find boards on the host's USB bus and tries to match them with serial ports and mounted drives, virtual or not. If drive_info
is True, when a drive is found, it reads circuitpython information if available: CPY version number and main files in order of priority (code.py, etc.). This might trigger the board's autoreload.
import discotool
devicesList = discotool.get_identified_devices(drive_info=True)
Devices list (MacOS)
[{
'manufacturer': 'Adafruit Industries LLC',
'name': 'CLUE nRF52840 Express',
'ports': [{
"dev": "'/dev/cu.usbmodem144443111'",
"iface": "CircuitPython CDC data"
}],
'product_id': 32882,
'serial_num': 'F88EE0399C0E1FC6',
'vendor_id': 9114,
'version': '6.0.1',
'volumes': [{
'mains': ['code.py'],
'mount_point': '/Volumes/CIRCUITPY',
'name': 'CIRCUITPY'
}],
'usb_location': '0x14630000'
}]
get_devices_list(drive_info=False)
: return a tuple of the devices list and the list of remaining unidentified serial ports(devicesList, remainingPorts)
.get_identified_devices(drive_info=False)
: only return the devices list.get_unidentified_ports()
: only return the unidentified serial ports.devices_by_name(name)
: only return the devices where the name contains the given string (not case sensitive).devices_by_drive(drive_name)
: only return the devices where the drive name (by default CIRCUITPY) is the given string.devices_by_serial(serial_number)
: only return the devices where the serial number is the given string (not case sensitive).
The device list is actually a list of DeviceInfoDict, a subclass of dictionary that adds a few properties as shortcuts for paths in the dictionary, with a default value of None
.
Dictionary entries:
name
: USB name of the board (str).manufacturer
: USB manufacturer of the board (str).product_id
: USB Product ID (int).vendor_id
: USB Vendor ID (int).serial_num
: USB Serial number of the board (str).version
: Circuitpython version, if found.ports
: list of serial ports found on the board, dictionaries.dev
: port device, used to connect to the port. COM port on windows, dev path on linux (str).iface
: interface name for the serial port (str).
volumes
: list of mounted drives from the board, dictionaries.name
: drive name, usuallyCIRCUITPY
for Circuitpython or*BOOT
for a UF2 bootloader drive (str).mount_point
: mount path of the drive, letter on windows (str).mains
: list of "main" files for Circuitpython (code.py etc.), by order of priority.
usb_location
: an identifier for the USB port the board is connected to, should be consistent across reboots and modes (bootloader/application).
Shortcuts:
repl
: REPL port, if any.data
: data port, if any.drive
andvolume
: board drive path.volume_name
: board drive name.vid
: shortcut forvendor_id
.pid
: shortcut forproduct_id
.