Post

ESP32 Debug Helper for macOS (with MicroPython)

ESP32 Debug Helper for macOS (with MicroPython)

Introduction

As a Linux administrator, I spend much of my time working on the command line. When I decided to dive back into ESP32 programming, I initially installed the Arduino IDE. However, I quickly realized I wanted a different way to interact with my ESP32 boards — one that better fit the way I like to work.

Since I planned to use MicroPython rather than C++ with Arduino, the toolchain around MicroPython felt like a better fit. My goal was to streamline the process of connecting, flashing, debugging, and running code without relying on heavyweight tools.


Table of Contents

  1. Introduction
  2. Working with mpremote
  3. The esp_debug.sh Script
  4. Flashing Firmware
  5. Uploading Code
  6. Running main.py
  7. Using the Serial Monitor
  8. Other Options
  9. Do You Really Need This?

Working with mpremote

One of the key utilities in the MicroPython ecosystem is mpremote, a command-line tool for interacting with ESP32 boards. It allows you to connect to the device, copy files, run scripts, reset the runtime, and more. Installing it (along with pyserial and esptool) is straightforward:

1
pip install mpremote pyserial esptool

mpremote quickly became invaluable. At first, I was copying and pasting commands into a terminal and keeping notes in a text editor. While this worked, it wasn’t very efficient. To streamline my workflow, I created a script called esp_debug.sh, which started as a way to open a MicroPython shell quickly — and then grew into a more complete utility.


The esp_debug.sh Script

The first task of esp_debug.sh is to check if an ESP32 is connected. It uses helper functions such as detect_port.sh to locate the correct /dev/cu.* device, and show_chip_type.sh to identify the ESP32 model. It also leverages data/serial_index.sh to map common ESP32 mount points.

Once the device is detected, the script provides an interactive shell menu:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
~/esp32/esp_debug.sh
[INFO] Using port: /dev/cu.usbserial-210
----------------------------------------------------------------
Detecting ESP chip type
----------------------------------------------------------------
[INFO] Detected chip: ESP32 (raw: ESP32-D0WD-V3)
[INFO] CHIP_TYPE set to: ESP32
--menu

ESP32 Debug Menu (port: /dev/cu.usbserial-210, chip: ESP32)
  1) Serial monitor
  3) Diagnostics snapshot
  4) Soft reset
  5) Run main.py
  6) Hard reset instructions
  f) Flash firmware
  u) Upload code to device
  q) Quit

The project layout keeps things modular:

1
2
3
4
5
esp32/
├── esp_debug.sh         # main script
├── micropython/         # firmware storage (optional)
├── functions/           # sourced helper functions
├── data/

This setup lets me do most of my ESP32 programming and debugging directly from the shell.


Flashing Firmware

The Flash Firmware option uses esptool to erase the ESP32’s flash memory with the erase-flash command.

⚠️ Note: Erasing the flash removes all prior programming, including the filesystem. Make sure you are prepared before using this option.

After wiping the chip, the script flashes a fresh copy of MicroPython based on the detected ESP32 type and the firmware stored in the micropython/ directory. Once complete, the ESP32 is ready to receive new code.


Uploading Code

To upload code, I run esp_debug.sh from my project directory. The script looks for a code/ subdirectory and uses mpremote to copy its contents — files and directories — to the ESP32.

This makes it simple to maintain project-specific source code while keeping the deployment process just one menu option away.


Running main.py

The Run main.py option executes the main.py script directly on the ESP32 within a serial monitor session. Any output generated by the script is displayed in real time, making it easy to spot errors or debug messages.

This feature was one of the primary reasons I created esp_debug.sh, as it allows me to quickly verify my code without extra manual steps.


Using the Serial Monitor

The Serial Monitor option drops you into the MicroPython REPL on the ESP32. Here, you can run commands interactively, test functions, and perform additional debugging.

It’s especially helpful for prototyping code, since you can import modules or classes and try them directly without reflashing the device. Typically, I run main.py first and then use the REPL to dig deeper into how the code is behaving.

💡 Note: If errors occur during a REPL session, you may be dropped out of the esp_debug.sh program.


Other Options

Several other useful features are included in the script:

  • Soft reset: Restarts the MicroPython runtime, rerunning boot.py without power cycling the device.
  • Diagnostics snapshot: Displays a quick overview of filesystem usage, memory, network configuration, and flash details.
  • Hard reset instructions: Provides guidance for performing a full hardware reset.

I continue to add new features as I discover needs in my workflow.


Do You Really Need This?

Strictly speaking, no — tools like mpremote and esptool are perfectly capable on their own. There are also more polished solutions out there.

But what I like about this approach is that it removes the friction of remembering command options and juggling multiple utilities. With esp_debug.sh, I can focus directly on writing and running MicroPython code, rather than worrying about the mechanics of flashing, resetting, or uploading.

For me, it’s about efficiency and staying in my preferred command-line workflow.

This post is licensed under CC BY 4.0 by the author.