Build, upload, and monitor your PlatformIO projects directly inside VS Code — with serial monitor, auto-reconnect, ESP32 backtrace decoder, and a full ESP32 chip security suite.

Highlights
- Verify & Upload — Build or flash your firmware with one click. Cancel mid-build at any time.
- Serial Monitor — Real-time serial output with auto-reconnect when the cable is unplugged and replugged. Ports appear automatically when a device is plugged in. Clear the monitor view with one click.
- Send Messages — Type and send commands to your device directly from the monitor. Navigate history with Up/Down arrows.
- Environment Selector — Switch between PlatformIO build environments without touching
platformio.ini.
- Build Variables — Define KEY/VALUE pairs in the VARIABLE tab. Each KEY in
src/ is replaced with its VALUE before every build, then restored after the build finishes. Saved to .pioconfig and auto-loaded next time. See Build Variables below.
- ESP32 Backtrace Decoder — Automatically detects Guru Meditation errors and decodes the backtrace into clickable source file links.
- DTR / RTS Control — Toggle DTR and RTS lines live without reconnecting. One-click Download Mode entry.
- PlatformIO Home — Open PlatformIO Home directly from the toolbar.
- Configurable Log Buffer — Set the maximum number of lines kept in Monitor and Log output.
- ESP32 Chip Security — Full security workflow for ESP32 chips: key generation, firmware signing, encrypted flash, OTA-safe setup, and permanent eFuse lock. See Chip Security below.
Requirements
- PlatformIO IDE extension installed.
- A workspace containing a
platformio.ini file (the panel appears automatically).
Usage
Build & Flash
| Button |
Action |
| VERIFY |
Build firmware without flashing |
| UPLOAD |
Build and flash to the connected device |
| ✕ Cancel |
Cancel the current build (appears during build) |
- Open a PlatformIO project — the PIO panel appears at the bottom of VS Code automatically.
- Select your environment from the dropdown (or leave it as Default).
- Click VERIFY to check for build errors, or UPLOAD to flash immediately.
- Build output appears in the LOG tab in real time.
Serial Monitor
- Plug in your device — the COM port appears in the port selector automatically (within ~1.5 seconds, no manual refresh needed).
- Select the baud rate to match your firmware's
Serial.begin(...) value.
- The monitor connects automatically after UPLOAD.
- To connect manually, click Connect.
| Control |
Description |
| ▶ Connect / ■ Disconnect |
Manually start or stop the serial connection |
| 🗑 Clear |
Clear the monitor output buffer |
| Send box |
Type a command and press Enter or click Send |
| ↑ / ↓ arrows |
Navigate the last 10 sent commands (like a terminal) |
| DTR / RTS |
Toggle hardware flow control lines live |
| ⬇ DL |
Enter ESP32 bootloader (download mode) without unplugging |
| Auto-reconnect |
Monitor reconnects automatically after a reset or cable replug |
Tip: Switching to the LOG, VARIABLE, or SETTINGS tab does not disconnect the serial monitor.
Build Variables
The VARIABLE tab lets you keep secrets and per-build values (Wi-Fi credentials, API tokens, server URLs, …) out of source control while still compiling them into the firmware.
- Open the VARIABLE tab.
- Click + Add variable and fill in
KEY and Value.
Repeat for each placeholder you want to substitute.
- Click VERIFY, UPLOAD, or Encrypt & Flash as usual.
What happens behind the scenes:
| Stage |
What the extension does |
| Before build |
Walks every text file under src/ (.c .cpp .h .hpp .ino .s …) and replaces every occurrence of each KEY with its VALUE. The original content is held in memory. |
| Build / Flash |
PlatformIO compiles the substituted source — the firmware binary contains the real values. |
| After build |
The original source files are written back automatically (success, failure, or cancel), so your KEY placeholders are preserved for the next build. |
Variables are stored in .pioconfig (JSON) at the workspace root and reloaded next time the panel opens. Add .pioconfig to .gitignore if it contains secrets.
Example: With key WIFI_SSID → MyNetwork, the line const char* ssid = "WIFI_SSID"; becomes const char* ssid = "MyNetwork"; for the build, and reverts to "WIFI_SSID" immediately after.
Variables apply to every build that produces firmware — Verify, Upload, and the Secure tab's Encrypt & Flash. Operations that don't rebuild (Sign Firmware, Check Status, Burn eFuse, …) use the binary from the previous build.
First-time path setup
If PlatformIO CLI is not detected automatically:
- Click the SETTINGS tab.
- Click Auto-detect — the extension searches common install locations.
- Or paste the full path to
pio / pio.exe, click Test, then Save.
ESP32 Chip Security
The SECURE tab provides a complete chip lock-down workflow for ESP32 / ESP32-S3 (and other ESP32 variants). All operations use esptool, espefuse, and espsecure from your PlatformIO installation — no extra setup required.
Tested on: ESP32-S3 with Arduino framework (PlatformIO). Other ESP32 variants (ESP32, S2, C3, C6, H2) are supported via chip auto-detection but have not been fully verified.
Warning — eFuse burns are PERMANENT and IRREVERSIBLE. Once burned, the chip cannot be unlocked. Always test with Encrypt & Flash before burning eFuses.
Security workflow overview
[SECURE tab]
Step 1 ──► Auto-detect tools
Step 2 ──► Generate signing key (.pem)
Step 3 ──► ⚙ Setup Secure Build ← configures platformio.ini
Step 4 ──► Rebuild project (pio run --target clean && pio run)
│
▼
Step 5 ──► Check Status ← verify chip is clean
Step 6 ──► Encrypt & Flash ← test: chip boots signed firmware
│
▼ only when working correctly
Step 7 ──► ⚠ Burn eFuse & Lock Chip ← PERMANENT
Click Auto-detect in the Tool Paths section. The extension finds esptool.py, espefuse.py, espsecure.py, and the PlatformIO Python from your ~/.platformio installation automatically.
If detection fails, paste the paths manually and click Save.
Step 2 — Generate signing key
Click Generate Key to create a new RSA-3072 private key for Secure Boot V2. The key is saved to keys/secure_boot_key.pem inside your workspace.
Keep secure_boot_key.pem safe. It is required to sign every firmware update (USB flash or OTA) after Secure Boot is enabled. If you lose it, you cannot update the firmware on locked chips.
To use an existing key, paste the path to the .pem file in the Signing Key field.
Step 3 — Setup Secure Build
Click ⚙ Setup Secure Build to configure your PlatformIO project for Secure Boot V2.
This writes board_build.cmake_extra_args into each [env:xxx] section of platformio.ini and creates sdkconfig.defaults:
| Config added |
Effect |
CONFIG_SECURE_BOOT_V2_ENABLED=y |
Bootloader compiled with signature verification code |
CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES=y |
PlatformIO auto-signs firmware.bin on every build |
CONFIG_SECURE_SIGNED_ON_UPDATE_NO_SECURE_BOOT=y |
App rejects unsigned OTA firmware before writing |
CONFIG_SECURE_BOOT_SIGNING_KEY=keys/...pem |
Key used for auto-signing |
Why this step is required: Without it, the bootloader does not contain signature verification code — so even with eFuses burned, unsigned firmware can still boot and unsigned OTA firmware is accepted.
If an env already has board_build.cmake_extra_args, it is skipped and a warning shown — merge the -DCONFIG_SECURE_BOOT_* flags manually.
Step 4 — Rebuild the project
After Setup Secure Build, rebuild from scratch so the new config takes effect:
pio run --target clean
pio run
Or use the VERIFY button (run clean manually first via terminal).
The build output (firmware.bin) will now be automatically signed by PlatformIO using your .pem key.
Step 5 — Check Status
Click Check Status to read the chip's current eFuse state. The output panel shows:
| Field |
Expected (clean chip) |
Expected (after burn) |
| Flash Encryption |
disabled |
ENABLED |
| Secure Boot V2 |
disabled |
ENABLED |
| JTAG |
enabled |
disabled |
| Download Mode |
enabled |
disabled (if selected) |
Use this to confirm the chip is clean before burning, and to verify after.
Step 6 — Encrypt & Flash
Click Encrypt & Flash to deploy firmware without burning eFuses. Use this to test that the chip boots the signed firmware correctly before making the lock permanent.
The sequence runs automatically:
- Build —
pio run with latest code
- Detect — reads chip encryption/secure boot state via
espefuse summary
- Sign — signs bootloader + firmware if Secure Boot is active
- Flash — uses the correct mode based on chip state:
| Chip state |
Flash method |
| No encryption |
Plain write_flash |
| Encryption ON, manual allowed |
write_flash --encrypt (chip encrypts in hardware) |
| Encryption ON, manual disabled |
Pre-encrypt with keys/flash_enc_key.bin, then flash |
The boot_app0.bin OTA data partition is always included to ensure the correct OTA slot is booted.
Verify the device reboots and runs correctly before proceeding to Step 7.
Step 7 — Burn eFuse & Lock Chip
Configure the eFuses to burn, then click ⚠ Burn eFuse & Lock Chip and confirm the dialog.
| Option |
Effect |
Reversible? |
| Disable JTAG debugging |
Blocks JTAG/SWD debug and memory dump |
❌ No |
| Enable Flash Encryption (Release) |
AES-128 encrypts all flash; firmware unreadable without chip key |
❌ No |
| Enable Secure Boot V2 |
Only firmware signed with your .pem key will boot |
❌ No |
| Read-protect eFuse key blocks |
Key material cannot be read back via software |
❌ No |
| Disable Download Mode |
Blocks all USB/UART re-flashing — OTA only after this |
❌ No |
After confirmation, the extension:
- Burns all selected eFuses in sequence
- Automatically runs Encrypt & Flash so the chip immediately boots the locked firmware
If a key block is already burned (read-protected), the step is safely skipped.
If Secure Boot key burning fails, the sequence aborts to prevent bricking.
OTA updates after locking
After the chip is locked with Secure Boot V2:
- OTA firmware must be signed with the same
.pem key
- Send
firmware.bin from your build output — it is auto-signed if Setup Secure Build was done
- Or sign manually: use Sign Firmware → send
output_secure/firmware_signed.bin
- The chip rejects unsigned OTA firmware before writing (if
CONFIG_SECURE_SIGNED_ON_UPDATE_NO_SECURE_BOOT=y is set)
- If Disable Download Mode was burned, USB/UART flashing is no longer possible — OTA is the only update path
File layout
<workspace>/
├── platformio.ini ← board_build.cmake_extra_args added by Setup Secure Build
├── sdkconfig.defaults ← fallback config (ESP-IDF / arduino-esp32 3.x)
├── .pioconfig ← Build Variables (KEY/VALUE pairs) for this workspace
├── keys/
│ ├── secure_boot_key.pem ← Signing key — KEEP SAFE, never commit to git
│ └── flash_enc_key.bin ← Flash Encryption key (auto-generated on burn)
└── output_secure/
├── firmware_signed.bin
├── bootloader_signed.bin
└── *_encrypted.bin ← Pre-encrypted files (DIS_DOWNLOAD_MANUAL_ENCRYPT case)
Add keys/, sdkconfig, and .pioconfig (if it holds secrets) to your .gitignore to avoid leaking private key material.
Settings
| Setting |
Default |
Description |
arduino.pioPath |
(auto) |
Full path to the PlatformIO CLI executable. Leave empty to auto-detect. |
arduino.maxLogLines |
200 |
Maximum lines kept in Monitor and Log output (50 – 10 000). |
arduino.secMaxLogLines |
1000 |
Maximum lines kept in Secure tab output (100 – 50 000). |
Tips
- Port auto-detection — ports appear automatically within ~1.5 s of plugging in a device, no refresh needed.
- Auto-reconnect — leave the monitor running; it reconnects automatically after a reset or cable replug.
- Backtrace links — click any decoded file path to jump directly to the offending line in your source.
- Cancel build — while building, the button turns into ✕ Cancel.
- Background monitor — switching to the Log, Variable, or Settings tab does not disconnect the serial monitor.
- Secure tab port — the Secure tab has its own port/environment selectors, independent of the monitor.
- Variable safety — source files are restored after every build (success, failure, or cancel) so your
KEY placeholders survive — commit them once and forget.
- Protect your key — add
keys/ to .gitignore. Anyone with secure_boot_key.pem can sign firmware for your locked chips.