MicroPython Developer Workflow

To have an efficient MicroPython workflow for your target device, you will want to have auto-completion, intellisense, a way to publish files to your device, access the MicroPython REPL, and manage packages.

MicroPython and VSCode

I do my development on MacOS, using the included Terminal program and default shell called Zshell. This works for me, I hope it works for you and helps you be more productive in your MicroPython projects.

Visual Studio Code

VSCode has great Python support and thus it has great MicroPython support. These extensions are required in my MicroPython workflow:

The Python Extension uses Black and Pylint to verify your code formatting and "correctness".

pip install black pylint

Quick Note on Extensions

I also work in Python and React-Native. I also use the Azure extensions for Serverless. That's a lot of extensions. To keep this clean, any time I install an extension I disable it globally. Then for every workspace, I enable the extensions I want for that specific project. You find the extension enable and disable menu by right clicking on the extension.

Meet the VSCode Python Team on Discord

The VSCode Python team just launched (May 2020) their own discord server. I hangout there and you can meet the Microsoft Team as well: https://discord.gg/VgMCcQ


Micropy-cli creates your workspace folder layout, sets up the VSCode (or PyMakr) settings, .gitignore, and manages the installation of stubs for your MicroPython port. Your project code will live in the src folder.

pip install micropy-cli

$ micropy init YOURPROJECT 

MicroPy  Creating New Project
? Choose any Templates to Generate
  (Use arrow keys to move, <space> to select, <a> to toggle, <i> to invert)           
 » ●  VSCode Settings for Autocompletion/Intellisense
   ○ Pymakr Configuration
   ●  Pylint MicroPython Settings
   ●  Git Ignore Template
   ●  main.py & boot.py files        

BEFORE you run init, add the stubs for your port and version of MicroPython. To see a list of stubs, search by your processor not your board. I have a TinyPico and I use the ESP32 stubs. As you can see, you won't find TinyPico, but you will find esp32.

$ micropy stubs search esp32      

MicroPy  Searching Stub Repositories...

MicroPy  Results for esp32:
MicroPy  esp32-micropython-1.10.0
MicroPy  esp32-micropython-1.11.0
MicroPy  esp32-micropython-1.12.0 (Installed)
MicroPy  esp32-micropython-1.9.4
MicroPy  esp32-pycopy-1.11.0
MicroPy  esp32-pycopy-
MicroPy  esp32-pycopy-
MicroPy  esp32-pycopy-3.0.0
MicroPy  esp32_LoBo
MicroPy  esp32_LoBo-esp32_LoBo-3.2.24

$ micropy stubs search tiny 

MicroPy  Searching Stub Repositories...

MicroPy  Results for tiny:
<blank line>

Copy the name of the stubs you want to add and run: micropy stubs add esp32-micropython-1.12.0

Once the stubs are added to your system, you run micropy init and choose the stubs you just added.

MicroPy  Creating New Project
? Choose any Templates to Generate  done (4 selections)                                                                 
? Which stubs would you like to use?  (Use arrow keys to move, <space> to select, <a> to toggle, <i> to invert)         
 » ● esp32-micropython-1.12.0

Stubs is Magic == True

Stubs are the magic that allow VSCode to have context when you're writing your code. This is more correctly called auto-complete and intellisense. I prefer to think of it as magic. There are many moving parts to make this work. Shout out to Magicians BradenM and Josverl for supporting the MicroPython community!


VScode will not see into your src/lib folder and it will break intellisense for packages. To correct this, add "src/lib" to the "python.autoComplete.extraPaths", "python.autoComplete.typeshedPaths" and "python.analysis.typeshedPaths" in your .vscode/settings.json.
This may no longer be neccesary if Micropy-cli Issue #96 is fixed.


uPip (pronounced micropip) is pip for MicroPython. To use uPip you must have MicroPython installed on your dev machine. The version you run our your dev machine is referred to as the Unix (or MacOs or Winows) Port as opposed to the microcontroller ports (ESP32, NRF, etc..). You can install MicroPython on MacOs using brew.

brew install micropython

Now you can run upip from within MicroPython

$ micropython -m upip                                             

upip - Simple PyPI package manager for MicroPython
Usage: micropython -m upip install [-p <path>] <package>... | -r <requirements.txt>
import upip; upip.install(package_or_list, [<path>])

If <path> is not given, packages will be installed into sys.path[1]
(can be set from MICROPYPATH environment variable, if current system supports that).
Current value of sys.path[1]: /Users/YOURACCOUNT/.micropython/lib

Note: only MicroPython packages (usually, named micropython-*) are supported
for installation, upip does not support arbitrary code in setup.py.

Taking packages from one port (your dev machine) to another port (your board) is called "cross-installing" in the official MicroPython documentation. To do that you use the -p flag to copy them to your project which you then copy to your board using Rshell. For example, to install micropython-lis2hh12, from the root of your project run: micropython -m upip install -p src/lib micropython-lis2hh12

Stubs for Packages

Micropy-cli will also add the stubs for your packages. Run micropy install <package-name> using the same package name as when you ran upip install.

Note: Micropy-cli does not install the package itself (upip does that). Micropy-cli is only installing the stubs at this point. There's an open feature request for this in GitHub.

Rshell: Remote Shell for MicroPython

Rshell is a cli tool to interact with files on your dev machine and your board. It also provides access to the board's MicroPython REPL.

pip install rshell

To connect to your board you will need to know the path to the serial port. With your board disconnected go the terminal and run ls -l /dev/tty.* then plugin your board and run it again. The new entry is your board. For my TinyPico it is /dev/tty.usbserial-01C86998. It will be different for different boards. Keep note of this we're going to need it.

In your project folder, run rshell. You will notice the prompt changed, you are now in rshell. Run connect serial /dev/tty.YOURDEVICE and you will see rshell connect. You should read the readme for rshell to understand all the commands, but I want to call out a couple of things:

  • ls shows your project folder
  • ls /pyboard shows your board's root directory. Your board is always /pyboard in rshell regardless of the actual name of your board. (PyBoard was the first MicroPython board.)
  • rsync src /pyboard -m is the command I use the most often. It copies ./src from my dev machine to the root of the device and removes and files from the device which are not in ./src
  • repl is the command you use to access the MicroPython REPL on your device. You can run code directly on your device and see all your print() output for debugging in the REPL.
  • Remembering that /dev/tty path is a PITA. If you only have ONE board, you can edit your .zshrc and add export RSHELL_PORT=/dev/tty.usbserial-01C86998. Now ever time you run rshell it will connect to that board. If you have more than one board, see the OhMyZSH Extensions section.
  • Type exit to leave rshell and go back to ZShell.

OhMyZsh Extenstions (optional)

OhMyZsh is pretty cool on its own and I highly recommend it. We're going to use it to deal with different boards. If you don't want to have to figure out the path to your device all the time and you have many boards, you will want to have different RSHELL_PORT valurs for different project folders. To do this, I use the OhMyZsh extension called Hab.

With OhMyZsh + Hab when I CD into a project folder, the RHSELL_port is set correclty and when I CD out of the project folder it is unset.

➜  ~ cd ~/code/github/tp-blescan
[SUCCESS]  Loaded hab [/Users/USER/code/github/tp-blescan/.envrc] (Last modified Mon May 18 13:20:13 PDT 2020)=
➜  tp-blescan cd ..
[WARN]     Unloaded variable RSHELL_PORT
➜  github 

When you do this, your current ~/.zshrc is moved to a file called ~/.zshrc.pre-oh-my-zsh and a new file will be started. You will need to copy and paste anything you had in it from ~/.zshrc.pre-oh-my-zsh back into ~/.zshrc.

  • Install ohMyZsh: sh -c "$(curl -fsSL https://raw.github.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"
  • Clone Hab into your ZSH Plugins folder git clone "https://github.com/alexdesousa/hab.git" "$ZSH_CUSTOM/plugins/hab"
  • Edit your new .zhrc and add hab to your plugins list (note no commas in the list, just spaces) and the autoaload commands as in the Hab docs.
autoload -U +X compinit && compinit
autoload -U +X bashcompinit && bashcompinit
autoload -U add-zsh-hook
plugins=(zsh-autosuggestions git pyenv hab)

I have extra plugins in my list, you will probably just have (git) and just add hab (git hab)

In your project folder, creae a file called .envrc with the following content:

# INHERIT: true

The Inherit line enables the setting to remain for sub-folders.

With that setup, when you launch rshell from your workspace, it will automatically connect AND you can have different boards for different workspaces. Magic + 1 !!

That's it!

This is just my workflow. You may be using a different shell or a different editor or Windows, or Linux. (I use those too). But for my MacOs dev machine, this has been working great for me. I hope you find it helpful as well!

If you need help with a project, reach out and let's discuss how PHIXED can help you. sales@phixed.co @askpatrickw