ESP32-C3 SuperMini Antenna Mod
ESP32-C3 SuperMini modules are remarkably affordable, but with a significantly restricted WiFi range. A simple antenna mod can improve its performance
ESP32-C3 SuperMini: Unleashing WiFi Potential with a Simple Mod and ANNEX32-BASIC

Testing and Results: Driven by ANNEX32-BASIC
Testing consistently showed an improvement of at least 6dB, and frequently exceeding 10dB! This makes WiFi much more reliable at a greater distance.
In theory, every 6dB doubles the free-line-of-sight range, assuming there are no obstructing objects or interference.
This is how the manufacturer Cross Air recommends to use the SMD antenna:

Conclusion:
Attached Images/Files:
- Close-up of the soldering points
- The WiFi logger test setup
- Performance graph
- Complete ANNEX32-BASIC Code for the WiFi Logger
A more elaborated blog post about this modification can be found at my <Blog>
If you are looking for an antenna mod regarding ESP32-S3-ZERO look HERE.
Forget all what you think to know about ancient BASIC dialects … It’s worth taking a look at the <ANNEX32 Firmware>.
The ANNEX32-BASIC script:
' This program compares the WiFi signal strengths (RSSI) of two ESP32 modules.
' It aims to graphically display the impact of different antennas on signal quality.
'
' - Module 1 (local): Displays its own signal strength to the Access Point (AP).
' - Module 2 (remote): Sends its signal strength to Module 1.
' Operation modes:
' RX = 1: This module (local) regularly sends HTTP requests to the remote module.
' TX = 1: This module (remote) responds to HTTP requests with its signal strength.
' Author: Peter Neufeld (peter.neufeld@gmx.de, 03/2025)
' Configuration for the local module (ESP32 Module 1):
RX = 1 ' This module sends requests to the remote module.
TX = 0 ' This module does not respond to requests.
' Configuration for the remote module (ESP32 Module 2):
'RX = 0 ' This module does not send requests.
'TX = 1 ' This module responds to requests.
REMOTE_IP$ = "192.168.0.134" ' IP address of the remote module (Module 2)
X_Num = 100 ' Number of measurements to display in the graph.
WIFI_REMOTE$ = "" ' Stores the received RSSI values from the remote module.
'onhtmlreload: Triggered when the webpage is reloaded.
onhtmlreload WEBPAGE
gosub WEBPAGE
' Enables URL handler for TX mode:
IF TX = 1 onurlmessage RETURN_WIFI_STRING
' Enables asynchronous HTTP requests in RX mode:
IF RX = 1 onwgetasync RECEIVE_REMOTE_STRING
' Timer to regularly measure local signal strength:
timer0 500, LOG_MY_WIFI_CONNECTION
' Timer to regularly query remote signal strength:
IF RX = 1 timer1 1000, GET_REMOTE_WIFI_LOG_STRING
WAIT
'###############################################################
LOG_MY_WIFI_CONNECTION:
' Measures local WiFi signal strength and stores it in WIFI_LOCAL$.
w=0
for i = 1 to 50
w = wifi.rssi + w ' Accumulates RSSI values for averaging.
next i
w = W / (i-1) ' Calculates the average RSSI value.
WIFI_LOCAL$ = trim$(WIFI_LOCAL$ + " " + str$(wifi.rssi,"%2.1f"))
c = word.count(WIFI_LOCAL$, " ") ' Counts stored values.
p = instr(1, WIFI_LOCAL$, " ") ' Finds the first value in the string.
p = len(WIFI_LOCAL$) - p ' Calculates the length of remaining values.
If c > X_Num then WIFI_LOCAL$ = right$(WIFI_LOCAL$, p) ' Limits the number of values.
' Updates the graph with local values:
jscall |traceme(0,"| + WIFI_LOCAL$ + |");|
' Updates the graph with remote values if available:
if WIFI_REMOTE$ <> "" jscall |traceme(1,"| + WIFI_REMOTE$ + |");|
return
'###############################################################
RETURN_WIFI_STRING:
' Returns local RSSI values as a response to an HTTP request.
URLMSGRETURN WIFI_LOCAL$
return
'###############################################################
GET_REMOTE_WIFI_LOG_STRING:
' Sends an HTTP request to the remote module to query its RSSI values.
wgetasync ("http://" + REMOTE_IP$ + "/msg?x=1")
return
'###############################################################
RECEIVE_REMOTE_STRING:
' Receives and stores the RSSI values from the remote module.
WIFI_REMOTE$ = WGETRESULT$
return
'###############################################################
WEBPAGE:
' Creates and loads the HTML page with the graph to display RSSI values.
cls
jsexternal "/xy.min.js" ' Loads external JavaScript library for graphs.
cnt = 0
a$ = ""
a$ = a$ + |
WiFi Graph for two ESP32 modules:
|
a$ = a$ + |GREEN: With additional antenna
RED: With standard antenna|
a$ = a$ + |
html a$
pause 500
A$ = ""
A$ = A$ + |var datasets = [|
A$ = A$ + | {|
A$ = A$ + | lineColor : 'rgba(20,100,100,1)',|
A$ = A$ + | pointColor : 'rgba(20,20,20,1)',|
A$ = A$ + | pointStrokeColor : '#fff',|
A$ = A$ + | data : []|
A$ = A$ + | },|
A$ = A$ + | {|
A$ = A$ + | lineColor : 'rgba(151,30,0,1)',|
A$ = A$ + | pointColor : 'rgba(151,80,0,1)',|
A$ = A$ + | pointStrokeColor : '#fff',|
A$ = A$ + | data : []|
A$ = A$ + | }|
A$ = A$ + |];|
A$ = A$ + |var ctx2 = document.getElementById('canvas1').getContext('2d');|
A$ = A$ + ||
A$ = A$ + |var xy = new Xy(ctx2, {rangeX:[0,|+ STR$(X_Num)+ |], rangeY:[-80,-35]|
A$ = A$ + |, smooth:0.05, pointCircleRadius:2, pointStrokeWidth:1 });|
A$ = A$ + ||
A$ = A$ + |function traceme(set, data){|
A$ = A$ + | var s = data.split(" ");|
A$ = A$ + | for (var i=0; i
A$ = A$ + | }|
A$ = A$ + | xy.draw(datasets);|
A$ = A$ + |}|
jscript A$
A$ = "" ' Frees memory.
return
If you want go extend the WIFI range of a classic ESP32 board, take a look at the LABs article „ESP32 Range Extender“
Build This Project
Bring this design to life with the Elektor PCB Service, powered by Eurocircuits. Upload the project files and order professionally manufactured PCBs or assembled boards through a proven European production platform.
Supporting KiCad, Eagle, Gerber, and ODB++ formats, the service is suitable for everything from prototypes and validation builds to series production and volume manufacturing.
Made in Europe. Fast. Reliable. Professional.

Discussion (3 comments)