Level up your TinyML skills

How to Write and Deploy Arduino sketches from Python

Automate Arduino sketches creation and deployment with Python and the arduino-cli

Write and Deploy Arduino sketches from Python

If you're an advanced Arduino user and experienced Python coder, you may gain a huge productivity boost in writing and deployment sketches thanks to this integration.

The everywhereml Python package is a wrapper around the arduino-cli and allows you to:

  1. generate Arduino sketches programmatically
  2. inject Python data into sketches
  3. compile and verify checkes
  4. upload to your board

How can these benefits turn into a productivity boost?

  1. you can generate a number of variations of the same sketch based on a configuration file
  2. you can integrate sketch compilation into your own build pipeline
  3. you can run benchmarks on many different boards
  4. you can create a script to flash many boards with ease

This page will function as a documentation page for how you can write, compile and deploy an Arduino sketch from Python.


You must have the Arduino CLI installed (refer to the documentation).

Then you must have the everywhereml Python package installed.

pip install everywhereml>=0.2.2

Create a sketch

The everywhereml implements a few simple classes to create a sketch, mainly to wrap the sketch files and the arduino-cli itself.

FILENAME: main.py

from everywhereml.arduino import Sketch, Ino, H """ Create a sketch object. A sketch is defined by: - a name (required) - a folder (optional) If you leave the folder empty, the current working directory will be used. You can use the special name ':system:' to use the default Arduino sketches folder (as reported by the command `arduino-cli config dump`) """ sketch = Sketch(name="PyDuino", folder=":system:") """ Then you can add files to the project (either the .ino main file or C++ header files) """ sketch += Ino(""" #include "hello.h" void setup() { Serial.begin(115200); } void loop() { hello(); delay(1000); } """) sketch += H("hello.h", """ void hello() { Serial.println("hello"); } """

Once the sketch is defined, you can compile it.

Compile a sketch

To compile the sketch, you need to set the board you want to compile for. You can either use the exact name or a partial search query: the library will try its best to find a match. If more than one is found, you can choose which one to use.

FILENAME: main.py

""" Compile sketch for Arduino Nano 33 BLE board. The board you target must appear in the `arduino-cli board listall` command. If you know the FQBN (Fully Qualified Board Name), you can use that too. """ if sketch.compile(board='Nano 33 BLE').is_successful: print('Log', sketch.output) print('Sketch stats', sketch.stats) else: print('ERROR', sketch.output)
Sketch uses 83888 bytes (8%) of program storage space. Maximum is 983040 bytes.
Global variables use 43920 bytes (16%) of dynamic memory, leaving 218224 bytes for local variables. Maximum is 262144 bytes.

Sketch stats
    {'compile_time': 8.248049780999736,
     'flash': 83888,
     'flash_max': 983040,
     'flash_percent': 0.08533528645833334,
     'ram': 43920,
     'ram_max': 262144,
     'ram_percent': 0.16754150390625}

The sketch.output attribute holds the response from the arduino-cli compile command (both on success or error).

The sketch.stats attribute holds a few statistics that can come useful for your own use-case:

  • compile_time: how long it took to compile the sketch
  • flash (with max and percent): how much flash space the sketch takes
  • ram (with max and percent): how much RAM memory the sketch takes

How you use these numbers is up to you.

I used them to create a benchmark of TinyML models on different boards, for example.

Upload a sketch

Last but not least, you can upload the sketch to your board.

FILENAME: main.py

""" You can specify the exact port """ sketch.upload(port='/dev/ttyUSB0') """ Or even part of it. The library will look for the best match. """ sketch.upload(port='ttyUSB') sketch.upload(port='/dev/cu.usbmodem') print(sketch.output)
dfu-util 0.10-dev

Copyright 2005-2009 Weston Schmidt, Harald Welte and OpenMoko Inc.
Copyright 2010-2021 Tormod Volden and Stefan Schmidt
This program is Free Software and has ABSOLUTELY NO WARRANTY
Please report bugs to http://sourceforge.net/p/dfu-util/tickets/

dfu-util: Warning: Invalid DFU suffix signature
dfu-util: A valid DFU suffix will be required in a future dfu-util release
Opening DFU capable USB device...
Device ID 2341:035b
Device DFU version 011a
Claiming USB DFU Interface...
Setting Alternate Interface #0 ...
Determining device status...
DFU state(2) = dfuIDLE, status(0) = No error condition is present
DFU mode device DFU version 011a
Device returned transfer size 4096
DfuSe interface name: "Internal Flash   "
Downloading element to address = 0x08040000, size = 136712
Erase   	[=========================] 100%       136712 bytes
Erase    done.
Download	[=========================] 100%       136712 bytes
Download done.
File downloaded successfully
Transitioning to dfuMANIFEST state

Pretty neat, don't you think?

Do you think this feature will supercharge your development flow?

Tell us in the comments!

Having troubles? Ask a question

Related posts


Machine Learning for MicroPython

Run your favourite Machine Learning algorithms on MicroPython and CircuitPython boards

Get monthly updates

Do not miss the next posts on TinyML and Esp32 camera. No spam, I promise

We use Mailchimp as our marketing platform. By submitting this form, you acknowledge that the information you provided will be transferred to Mailchimp for processing in accordance with their terms of use. We will use your email to send you updates relevant to this website.

Having troubles? Ask a question

© Copyright 2023 Eloquent Arduino. All Rights Reserved.