baldaquin.arduino_ — Arduino interface#

This module provides minimal support for interacting with the Arduino ecosystem, the basic idea is that we start with Arduino UNO and we add on more boards as we need them.

See also

In order to fully utilize the facilities in this module you will need at least some additional third-paryt software. The following links are relevant for operating with Arduino boards.

Since nowadays the Arduino CLI seems to be the preferred way to interact programmatically with the Arduino ecosystem, we will assume that is the default choice. If you have arduino-cli installed you should be good to go—see the installation instructions. (This will literally run a script and copy the executable on your machine, which is handy because you will not need administrator priviledges to run the thing. The same thing holds for all the additional modules, e.g., arduino:avr you might need.)

The ArduinoBoard class provides a small container encapsulating all the information we need to interact with a board, most notably the list of DeviceId for the latter (that can be used to auto-detect boards attached to a COM port), as well as the relevant parameters to upload sketches on it.

A small database internal to the class contains a list of boards that we support, and which can be retrieved either by DeviceId or by designator:

>>> board = ArduinoBoard.by_device_id(DeviceId(0x2341, 0x43))
>>> print(board)
ArduinoBoard(designator='uno', name='Arduino UNO', vendor='arduino',
    architecture='avr', upload_protocol='arduino', upload_speed=115200,
    build_mcu='atmega328p', device_ids=((vid=0x2341, pid=0x43),
    (vid=0x2341, pid=0x1), (vid=0x2a03, pid=0x43), (vid=0x2341, pid=0x243),
    (vid=0x2341, pid=0x6a)))
>>>
>>> board = ArduinoBoard.by_designator('uno')
>>> print(board)
ArduinoBoard(designator='uno', name='Arduino UNO', vendor='arduino',
    architecture='avr', upload_protocol='arduino', upload_speed=115200,
    build_mcu='atmega328p', device_ids=((vid=0x2341, pid=0x43),
    (vid=0x2341, pid=0x1), (vid=0x2a03, pid=0x43), (vid=0x2341, pid=0x243),
    (vid=0x2341, pid=0x6a)))

Auto-detecting boards#

The module comes with a couple of utilities to help auto-detecting boards.

autodetect_arduino_boards() will look over all the COM ports and identify all the supported Arduino boards connected. An arbitrary number of board objects can be passed to the function, and they will act as a filter for the boards that are actually returned. If, e.g., you are interested in all the Arduino UNOs connected, you can do something along the lines of:

>>> ports = arduino_.autodetect_arduino_boards(arduino_.UNO)
>>> [INFO] Autodetecting Arduino boards ['Arduino UNO']...
>>> [INFO] Scanning serial devices...
>>> [DEBUG] Port(name='/dev/ttyS0', device_id=(vid=None, pid=None), manufacturer=None)
>>> [DEBUG] Port(name='/dev/ttyACM0', device_id=(vid=0x2341, pid=0x43), manufacturer='Arduino (www.arduino.cc)')
>>> [INFO] Done, 2 device(s) found.
>>> [INFO] Filtering port list for specific devices: [(vid=0x2341, pid=0x43), (vid=0x2341, pid=0x1), (vid=0x2a03, pid=0x43), (vid=0x2341, pid=0x243), (vid=0x2341, pid=0x6a)]...
>>> [INFO] Done, 1 device(s) remaining.
>>> [DEBUG] Port(name='/dev/ttyACM0', device_id=(vid=0x2341, pid=0x43), manufacturer='Arduino (www.arduino.cc)')
>>> [DEBUG] /dev/ttyACM0 -> uno (Arduino UNO)
>>>
>>> print(ports)
>>> [Port(name='/dev/ttyACM0', device_id=(vid=0x2341, pid=0x43), manufacturer='Arduino (www.arduino.cc)')]

The function returns a list of Port objects, that are ready to use.

In many cases you might be interested in a single board, in which case you can use the autodetect_arduino_board(), variant. This will return the first board that is found, and log a warning if more than one is connected.

These two functions can be integrated in complex workflows as needed.

Uploading sketches#

This module implements two diffent interfaces to programmatically upload sketches onto a connected Arduino board:

  • ArduinoCli, wrapping the Arduino command-line interface;

  • AvrDude, wrapping avrdude.

As alerady said earlier on, we shall assume that arduino-cli is the preferred way to do business. In most cases you can simply use the top-level interface upload_sketch() to upload a sketch onto an Arduino board connected to the computer.

Compiling sketches#

The module also provides a way to compile sketches, using the simple, top-level interface compile_sketch().

Module documentation#

Arduino common resources.

class baldaquin.arduino_.ArduinoBoard(designator: str, name: str, vendor: str, architecture: str, upload_protocol: str, upload_speed: int, build_mcu: str, device_ids: tuple[DeviceId])[source]#

Small container class representing a specific Arduino board.

This is not supposed as a mean to replicate all the functionalities of the Arduino CLI—on the contrary, we want to include here the bare minimum that is necessary in order to do simple things, e.g., auto-recognize Arduino boards attached to the serial port and programmatically upload a sketch.

The ultimate reference for all this information is embedded into the (platform-specific) boards.txt file, e.g., arduino/ArduinoCore-avr Rather than parsing the entire file and come up with a parallel Python structure supporting all the boards on the face of the Earth, we decided to manually add the necessary data for specific boards only when (and if) we need them, starting from the Arduino UNO, being used in plasduino.

The typical entry in the file for a board is something like this:

uno.name=Arduino UNO

uno.vid.0=0x2341
uno.pid.0=0x0043
uno.vid.1=0x2341
uno.pid.1=0x0001
uno.vid.2=0x2A03
uno.pid.2=0x0043
uno.vid.3=0x2341
uno.pid.3=0x0243
uno.vid.4=0x2341
uno.pid.4=0x006A
uno.upload_port.0.vid=0x2341
uno.upload_port.0.pid=0x0043
uno.upload_port.1.vid=0x2341
uno.upload_port.1.pid=0x0001
uno.upload_port.2.vid=0x2A03
uno.upload_port.2.pid=0x0043
uno.upload_port.3.vid=0x2341
uno.upload_port.3.pid=0x0243
uno.upload_port.4.vid=0x2341
uno.upload_port.4.pid=0x006A
uno.upload_port.5.board=uno

uno.upload.tool=avrdude
uno.upload.tool.default=avrdude
uno.upload.tool.network=arduino_ota
uno.upload.protocol=arduino
uno.upload.maximum_size=32256
uno.upload.maximum_data_size=2048
uno.upload.speed=115200

uno.bootloader.tool=avrdude
uno.bootloader.tool.default=avrdude
uno.bootloader.low_fuses=0xFF
uno.bootloader.high_fuses=0xDE
uno.bootloader.extended_fuses=0xFD
uno.bootloader.unlock_bits=0x3F
uno.bootloader.lock_bits=0x0F
uno.bootloader.file=optiboot/optiboot_atmega328.hex

uno.build.mcu=atmega328p
uno.build.f_cpu=16000000L
uno.build.board=AVR_UNO
uno.build.core=arduino
uno.build.variant=standard

Note that we refer to the qualifier for the board (“uno” in this case) as the board designator, and we parse the bare minimum of the information from the file.

designator: str#
name: str#
vendor: str#
architecture: str#
upload_protocol: str#
upload_speed: int#
build_mcu: str#
device_ids: tuple[DeviceId]#
fqbn() str[source]#

Return the fully qualified board name (FQBN), as defined in https://arduino.github.io/arduino-cli/1.1/platform-specification/

static concatenate_device_ids(*boards: ArduinoBoard) tuple[DeviceId][source]#

Return a tuple with all the possible DeviceId objects corresponding to a subset of the supported arduino boards.

Parameters:

*boards (ArduinoBoard) – The ArduinoBoard object(s) we are interested into.

Returns:

A tuple of DeviceId objects.

Return type:

tuple

static by_device_id(device_id: DeviceId) ArduinoBoard[source]#

Return the ArduinoBoard object corresponding to a given DeviceId.

Note this only involves a dictionary lookup, and nothing is created on the spot.

Parameters:
  • vid (int) – The vendor ID for the given device.

  • pid (int) – The prodict ID for the given device.

Returns:

The ArduinoBoard object corresponding to the DeviceId.

Return type:

ArduinoBoard

static by_designator(designator: str) ArduinoBoard[source]#

Return the ArduinoBoard object corresponding to a given (vid, pid) tuple.

Note this only involves a dictionary lookup, and nothing is created on the spot.

Parameters:

designator (str) – The board designator (e.g., “uno”).

Returns:

The ArduinoBoard object corresponding to the designator.

Return type:

ArduinoBoard

baldaquin.arduino_.autodetect_arduino_boards(*boards: ArduinoBoard) list[Port][source]#

Autodetect all supported arduino boards of one or more specific types attached to the COM ports.

Parameters:

*boards (ArduinoBoard) – The ArduinoBoard object(s) we are interested into.

Returns:

The list of Port object with relevant boards attached to them.

Return type:

list of Port objects

baldaquin.arduino_.autodetect_arduino_board(*boards: ArduinoBoard) Port[source]#

Autodetect the first supported arduino board within a list of board types.

Note this returns None if no supported arduino board is found, and the first board found in case there are more than one.

Parameters:

*boards (ArduinoBoard) – The ArduinoBoard object(s) we are interested into.

Returns:

The Port object our target board is attached to.

Return type:

Port

class baldaquin.arduino_.ArduinoProgrammingInterfaceBase[source]#

Basic class for concrete interfaces for programming Arduino devices.

PROGRAM_NAME = None#
PROGRAM_URL = None#
static upload(file_path: str, port: str, board: ArduinoBoard, **kwargs) CompletedProcess[source]#

Do nothing method, to be reimplented in derived classes.

classmethod _execute(args) CompletedProcess[source]#

Execute a shell command.

This is wrapping the basic subprocess functionality, adding some simple diagnostics. Note a CalledProcessError exception is raised if the underlying program returns an error code different from zero.

Parameters:

args (any) – All the arguments passed to subprocess.run().

Returns:

The CompletedProcess object.

Return type:

subprocess.CompletedProcess

class baldaquin.arduino_.ArduinoCli[source]#

Poor-man Python interface to the Arduino-CLI.

The installation instructions for the arduino command-line interface are at https://arduino.github.io/arduino-cli/1.1/installation/

(At least on GNU/Linux) this points to a single file that you can just place wherever your $PATH will reach it. For the records: when I run the thing for the first time (uploading a sketch to an Arduino UNO) it immediately prompted me to install more stuff

>>> arduino-cli core install arduino:avr

(which I guess is fine, but it is weighing in as to what we should suggest users to install).

PROGRAM_NAME = 'arduino-cli'#
PROGRAM_URL = 'https://github.com/arduino/arduino-cli'#
static upload(file_path: str, port: str, board: ArduinoBoard, verbose: bool = False) CompletedProcess[source]#

Upload a sketch to a board.

Note this is using avrdude under the hood.

Usage:
  arduino-cli upload [flags]

Examples:
  arduino-cli upload /home/user/Arduino/MySketch -p /dev/ttyACM0 -b arduino:avr:uno
  arduino-cli upload -p 192.168.10.1 -b arduino:avr:uno --upload-field password=abc

Flags:
      --board-options strings         List of board options separated by commas. Or can be used multiple times for multiple options.
      --build-path string             Directory containing binaries to upload.
      --discovery-timeout duration    Max time to wait for port discovery, e.g.: 30s, 1m (default 1s)
  -b, --fqbn string                   Fully Qualified Board Name, e.g.: arduino:avr:uno
  -h, --help                          help for upload
      --input-dir string              Directory containing binaries to upload.
  -i, --input-file string             Binary file to upload.
  -p, --port string                   Upload port address, e.g.: COM3 or /dev/ttyACM2
  -m, --profile string                Sketch profile to use
  -P, --programmer string             Programmer to use, e.g: atmel_ice
  -l, --protocol string               Upload port protocol, e.g: serial
  -F, --upload-field key=value        Set a value for a field required to upload.
      --upload-property stringArray   Override an upload property with a custom value. Can be used multiple times for multiple properties.
  -v, --verbose                       Optional, turns on verbose mode.
  -t, --verify                        Verify uploaded binary after the upload.

Global Flags:
      --additional-urls strings   Comma-separated list of additional URLs for the Boards Manager.
      --config-dir string         Sets the default data directory (Arduino CLI will look for configuration file in this directory).
      --config-file string        The custom config file (if not specified the default will be used).
      --json                      Print the output in JSON format.
      --log                       Print the logs on the standard output.
      --log-file string           Path to the file where logs will be written.
      --log-format string         The output format for the logs, can be: text, json (default "text")
      --log-level string          Messages with this level and above will be logged. Valid levels are: trace, debug, info, warn, error, fatal, panic (default "info")
      --no-color                  Disable colored output.
static compile(file_path: str, output_dir: str, board: ArduinoBoard, verbose: bool = False) CompletedProcess[source]#

Compile a sketch.

Usage:
  arduino-cli compile [flags]

Examples:
  arduino-cli compile -b arduino:avr:uno /home/user/Arduino/MySketch
  arduino-cli compile -b arduino:avr:uno --build-property "build.extra_flags="-DMY_DEFINE="hello world""" /home/user/Arduino/MySketch
  arduino-cli compile -b arduino:avr:uno --build-property "build.extra_flags=-DPIN=2 "-DMY_DEFINE="hello world""" /home/user/Arduino/MySketch
  arduino-cli compile -b arduino:avr:uno --build-property build.extra_flags=-DPIN=2 --build-property "compiler.cpp.extra_flags="-DSSID="hello world""" /home/user/Arduino/MySketch


Flags:
      --board-options strings                 List of board options separated by commas. Or can be used multiple times for multiple options.
      --build-path string                     Path where to save compiled files. If omitted, a directory will be created in the default temporary path of your OS.
      --build-property stringArray            Override a build property with a custom value. Can be used multiple times for multiple properties.
      --clean                                 Optional, cleanup the build folder and do not use any cached build.
      --discovery-timeout duration            Max time to wait for port discovery, e.g.: 30s, 1m (default 1s)
      --dump-profile                          Create and print a profile configuration from the build.
      --encrypt-key string                    The name of the custom encryption key to use to encrypt a binary during the compile process. Used only by the platforms that support it.
  -e, --export-binaries                       If set built binaries will be exported to the sketch folder.
  -b, --fqbn string                           Fully Qualified Board Name, e.g.: arduino:avr:uno
  -h, --help                                  help for compile
  -j, --jobs int32                            Max number of parallel compiles. If set to 0 the number of available CPUs cores will be used.
      --keys-keychain string                  The path of the dir to search for the custom keys to sign and encrypt a binary. Used only by the platforms that support it.
      --libraries strings                     Path to a collection of libraries. Can be used multiple times or entries can be comma separated.
      --library strings                       Path to a single library’s root folder. Can be used multiple times or entries can be comma separated.
      --only-compilation-database             Just produce the compilation database, without actually compiling. All build commands are skipped except pre* hooks.
      --optimize-for-debug                    Optional, optimize compile output for debugging, rather than for release.
      --output-dir string                     Save build artifacts in this directory.
  -p, --port string                           Upload port address, e.g.: COM3 or /dev/ttyACM2
      --preprocess                            Print preprocessed code to stdout instead of compiling.
  -m, --profile string                        Sketch profile to use
  -P, --programmer string                     Programmer to use, e.g: atmel_ice
  -l, --protocol string                       Upload port protocol, e.g: serial
      --quiet                                 Optional, suppresses almost every output.
      --show-properties string[="expanded"]   Show build properties. The properties are expanded, use "--show-properties=unexpanded" if you want them exactly as they are defined. (default "disabled")
      --sign-key string                       The name of the custom signing key to use to sign a binary during the compile process. Used only by the platforms that support it.
  -u, --upload                                Upload the binary after the compilation.
  -v, --verbose                               Optional, turns on verbose mode.
  -t, --verify                                Verify uploaded binary after the upload.
      --warnings string                       Optional, can be: none, default, more, all. Used to tell gcc which warning level to use (-W flag). (default "none")

Global Flags:
      --additional-urls strings   Comma-separated list of additional URLs for the Boards Manager.
      --config-dir string         Sets the default data directory (Arduino CLI will look for configuration file in this directory).
      --config-file string        The custom config file (if not specified the default will be used).
      --json                      Print the output in JSON format.
      --log                       Print the logs on the standard output.
      --log-file string           Path to the file where logs will be written.
      --log-format string         The output format for the logs, can be: text, json (default "text")
      --log-level string          Messages with this level and above will be logged. Valid levels are: trace, debug, info, warn, error, fatal, panic (default "info")
      --no-color                  Disable colored output.
class baldaquin.arduino_.AvrDude[source]#

Poor-man Python interface to the avrdude.

Usage: avrdude [options]
    Options:
      -p <partno>                Required. Specify AVR device.
      -b <baudrate>              Override RS-232 baud rate.
      -B <bitclock>              Specify JTAG/STK500v2 bit clock period (us).
      -C <config-file>           Specify location of configuration file.
      -c <programmer>            Specify programmer type.
      -D                         Disable auto erase for flash memory
      -i <delay>                 ISP Clock Delay [in microseconds]
      -P <port>                  Specify connection port.
      -F                         Override invalid signature check.
      -e                         Perform a chip erase.
      -O                         Perform RC oscillator calibration (see AVR053).
      -U <memtype>:r|w|v:<filename>[:format]
                                 Memory operation specification.
                                 Multiple -U options are allowed, each request
                                 is performed in the order specified.
      -n                         Do not write anything to the device.
      -V                         Do not verify.
      -u                         Disable safemode, default when running from a script.
      -s                         Silent safemode operation, will not ask you if
                                 fuses should be changed back.
      -t                         Enter terminal mode.
      -E <exitspec>[,<exitspec>] List programmer exit specifications.
      -x <extended_param>        Pass <extended_param> to programmer.
      -v                         Verbose output. -v -v for more.
      -q                         Quell progress output. -q -q for less.
      -l logfile                 Use logfile rather than stderr for diagnostics.
      -?                         Display this usage.

    avrdude version 6.4, URL: <http://savannah.nongnu.org/projects/avrdude/>
PROGRAM_NAME = 'avrdude'#
PROGRAM_URL = 'https://github.com/avrdudes/avrdude'#
static upload(file_path: str, port: str, board: ArduinoBoard, verbose: bool = False) CompletedProcess[source]#

Upload a sketch to a board.

baldaquin.arduino_.upload_sketch(file_path: str, board_designator: str, port_name: str | None = None, verbose: bool = False) CompletedProcess[source]#

High-level interface to upload a compiled sketch to an arduino board.

Parameters:
  • file_path (str) – The path to the binary file containing the sketch compiled for the given board.

  • board_designator (str) – The board designator (e.g., “uno”).

  • port_name (str, optional) – The port name the board is attached to (e.g., “/dev/ttyACM0”). If this is None, we use the autodetection features implemented in the module.

  • verbose (bool) – If True, the program will run in verbose mode.

baldaquin.arduino_.compile_sketch(file_path: str, board_designator: str, output_dir: str, verbose: bool = False) CompletedProcess[source]#

High-level interface to compile a sketch for a given arduino board.

Parameters:
  • file_path (str) – The path to the binary file containing the sketch compiled for the given board. Note that, in virtue of some interesting decision by the Arduino team, it appears that the main source file for the sketch should be embedded in a folder with the same name (without extension)—I guess that vaguely makes sense for sketches with multiple files. The directory name is also gladly accepted for the compilation.

  • board_designator (str) – The board designator (e.g., “uno”).

  • otuput_dir (str) – Path to the folder where the compilation artifacts should be placed.

  • verbose (bool) – If True, the program will run in verbose mode.