<- Back

ESP-NOW: The Protocol That Saved My IoT Project

When WiFi and Bluetooth fought for resources on a single ESP32, my car telemetry project kept crashing. Here's how ESP-NOW and a dual-microcontroller architecture solved the race condition problem.

I thought I was being clever. One ESP32, two radios, infinite possibilities. My car telemetry project would use Bluetooth to read data from the OBD-II port while simultaneously publishing it to the cloud over WiFi. What could go wrong?

Everything, as it turned out.

The system would work for a few minutes, then randomly disconnect from either the car or the internet. Sometimes both. The crashes were impossible to reproduce consistently. Welcome to the world of race conditions in embedded systems.

The solution? Stop forcing one chip to do two jobs, and connect two specialized ESP32s with a protocol called ESP-NOW. Here's what I learned.

What is ESP-NOW?

ESP-NOW is a fast, connectionless communication protocol developed by Espressif for ESP microcontrollers (ESP8266 and ESP32). Think of it as a wireless cable between devices that lets them talk directly without needing a WiFi router in the middle.

Key features:

  • Fast and low-latency: No connection handshake means data goes out immediately
  • Peer-to-peer: Devices talk directly using MAC addresses, no router needed
  • Long-range: Works on 2.4GHz WiFi and can reach 100+ meters
  • Flexible topologies: Supports one-to-one, one-to-many, and many-to-one communication

It's not meant to replace WiFi or Bluetooth for their primary use cases. Instead, it fills a specific niche: fast, simple communication between nearby devices that you control.

The Problem: When One Chip Isn't Enough

My TSI-Telemetry project had a simple goal: read diagnostic data from my car's OBD-II port via Bluetooth and publish it to HiveMQ Cloud via MQTT over WiFi. I wanted to do this on a single ESP32 to keep costs down.

Here's what I needed the chip to do simultaneously:

  1. Maintain a BLE connection to the ELM327 OBD-II adapter and constantly request fresh data
  2. Maintain a WiFi connection to my phone's hotspot
  3. Publish data via MQTT with TLS encryption for security

This created three critical problems:

Radio conflict: The ESP32 has a single 2.4GHz radio antenna that must rapidly switch between WiFi and Bluetooth. When both protocols are active and demanding, the antenna can't keep up. Packets get dropped. Connections timeout.

Memory exhaustion: Both WiFi and Bluetooth stacks are memory-hungry. The TLS encryption for MQTT makes it worse. Running all three simultaneously pushed the ESP32 to its limits, causing random crashes when memory ran out.

CPU starvation: TLS encryption is computationally expensive. When the WiFi task was encrypting and sending data, it would hog the CPU. The Bluetooth task wouldn't get enough processing time to maintain its connection to the car, and the OBD-II adapter would disconnect.

The result was a system that worked beautifully in isolation but fell apart under real-world conditions. I could get Bluetooth working reliably, or WiFi working reliably, but not both at the same time.

The Solution: Divide and Conquer with ESP-NOW

Instead of forcing one chip to multitask, I split the responsibilities across two ESP32s and connected them with ESP-NOW:

┌─────────────────┐    ESP-NOW     ┌─────────────────┐
│   OBD Sender    │───────────────►│  MQTT Receiver  │
│    (ESP32 #1)   │                │    (ESP32 #2)   │
│                 │                │                 │
│  - BLE only     │                │  - WiFi only    │
│  - Heavy lifting│                │  - Network tasks│
└─────────────────┘                └─────────────────┘

ESP32 #1 (OBD Sender): This chip has one job and one job only—maintain the Bluetooth connection to the car. It dedicates 100% of its resources to reading OBD-II data, parsing it, and packaging it up. When it has data ready, it sends it via ESP-NOW to the known MAC address of its partner chip. It doesn't know about WiFi, MQTT, or the internet. It doesn't need to.

ESP32 #2 (MQTT Receiver): This chip also has one job—manage the network. It maintains the WiFi connection and the secure MQTT link to HiveMQ Cloud. When it receives a packet via ESP-NOW, it forwards it to the cloud. That's it.

ESP-NOW acts as a wireless data cable between them. It's fast enough that there's no noticeable latency, and it's reliable enough that I haven't seen a single dropped packet in production.

Why This Architecture Works

Separation of concerns: Each chip does exactly one complex thing. The code on each microcontroller became simpler because it no longer had to juggle competing tasks.

Dedicated resources: The BLE chip never has to share its radio, memory, or CPU with WiFi tasks. The WiFi chip never has to worry about Bluetooth timing. Both run smoothly because they're not fighting for resources.

Easier debugging: When something goes wrong, I know exactly which chip to look at. Connection to the car lost? Check ESP32 #1. Can't reach the cloud? Check ESP32 #2.

Better reliability: Since deploying this architecture, the system has been rock solid. No more random disconnects. No more race conditions. Just consistent, predictable behavior.

The Tradeoff

Yes, I'm using two microcontrollers instead of one. That adds cost (about $4 per ESP32) and board space. But the reliability gain is worth it. The alternative was spending weeks trying to tune FreeRTOS task priorities, memory allocations, and radio timing to make a single-chip solution work—with no guarantee of success.

Sometimes the right engineering decision is to stop fighting the hardware and work with it instead.

Key Takeaways

  • ESP-NOW is perfect for device-to-device communication when you control both endpoints and need low latency
  • Race conditions in embedded systems are brutal and often manifest as random, hard-to-reproduce failures
  • Separation of concerns isn't just good software design—it applies to hardware architecture too
  • Adding a second cheap microcontroller can be simpler than trying to optimize a single overloaded one

If you're building an IoT project and finding that WiFi and Bluetooth don't play nicely together on a single ESP32, consider splitting them across two chips with ESP-NOW as the bridge. Your future self will thank you when the system just works.