Hello friends, I hope you all are doing great. Today, I am going to share the AirLift ESP32 Breakout Library for Proteus. The AirLift breakout is a small board with an ESP32 Wi-Fi co-processor that any microcontroller can use over SPI. The ESP32 runs the NINA firmware, and your Arduino sketch talks to it with the WiFiNINA library: WiFi.begin(), WiFiClient, WiFiSSLClient, WiFi.getTime() and the rest. With this library you can place the breakout in Proteus, wire it to our UNO with six signal wires and run a WiFiNINA sketch as it is.

Updates

AirLift ESP32 Breakout Library for Proteus

Latest version: V1.0 (October 2026, this tutorial)

Other ESP32 boards and modules: ESP32 DevKit V1 · ESP32-DevKitC V4 · ESP32-S3 DevKitC-1 · ESP32-C3 SuperMini · TTGO T-Display · ESP32-WROOM-32 · AirLift WiFi Shield

ESP8266 modules: ESP-01 · ESP-01S · ESP-07 · ESP-07S · ESP-12E · ESP-12F · ESP-01 Adapter · WiFi Shield · NodeMCU · NodeMCU V2 · D1 Mini

Helping Tools

This is the fifteenth library of our Wi-Fi series and the little brother of our AirLift WiFi Shield Library for Proteus: the same ESP32 and the same firmware, but on a 33 x 32 mm breakout that you wire yourself. Its demo shows the internet side of WiFiNINA - the time from the internet, a DNS look-up, a ping and an HTTPS upload to a cloud server every 20 seconds - with a status page for our Laptop WiFi Monitor and Mobile WiFi Monitor. The breakout's own pins are modelled too: GP0 as the ESP32's boot strap and TXO with the ESP32's boot text.

NOTICE: the PWR and SPI LEDs and the PANEL pad of our breakout are TEP additions; the access point mode, real TLS and Bluetooth are not simulated (see the limits at the end). Use the Adafruit version of WiFiNINA with WiFi.setPins(). Your feedback is the fuel that keeps us going, so please tell us what you think in the comments below or in the AirLift ESP32 Breakout board of our forum. And if our free libraries help you, you can buy us a coffee. So, let's get started with the AirLift ESP32 Breakout Library for Proteus:

Figure: The AirLift ESP32 Breakout Library for Proteus: the breakout (U1) with its blue LED on during an upload and the antenna sending; the phone's page after UPLOAD NOW, the UNO's monitor and the panel's cloud tab of the same demo.

What is the AirLift ESP32 Breakout?

The AirLift boards (made by Adafruit) carry an ESP32-WROOM-32 module flashed with a version of the NINA firmware - the firmware of the u-blox NINA-W102 module on Arduino's own Wi-Fi boards. The ESP32 does not run your sketch: it is a Wi-Fi modem that your microcontroller controls over SPI. The breakout adds a 3.3 V regulator, level shifting for 5 V boards, a tri-state buffer on MISO so the SPI bus can be shared, three tiny LEDs and a 12-pin header.

The real AirLift ESP32 breakout and the AirLift ESP32 Breakout in Proteus
Real AirLift ESP32 breakoutThis library in Proteus
Wi-Fi chipESP32-WROOM-32 with the NINA firmwareour NINA firmware model (version 1.7.4, a property)
Size33.0 x 31.8 mmdrawn at the real size
LinkSPI + CS, BUSY, !RESET (level-shifted)SPI + CS, BUSY, !RST - wired to D13 / D12 / D11, D10, D7, D5
Arduino libraryWiFiNINA (the Adafruit fork)the same library, unchanged
LEDsred, green and blue on the ESP32, WiFi.setLEDs()the same three LEDs, each as bright as its value
GP0, RXI, TXOthe bootloader, BLE and firmware updatesGP0 as the boot strap, TXO with the ROM's boot text
Extra LEDsnonea red PWR LED and an orange SPI LED (TEP additions)
SupplyVIN 3.3 - 5 V, up to 250 mA, 3Vo outVIN and GND; 3Vo HIGH while powered

NINA: a Wi-Fi Co-processor on SPI

Our AT modules - the ESP32-WROOM-32 Library for Proteus, for example - take text commands on a serial port. NINA is different: every WiFiNINA function becomes a short binary command frame on SPI (start byte, command, parameters, end byte) and the ESP32 answers with a reply frame. WiFi.status() is one command, an HTTPS request is a handful (open the socket, send the request, read the answer, close), and the library asks "is there data?" in every pass of loop(). In our demo the UNO sends about 5000 commands a second.

The Pins of the Breakout

All twelve pins are on one edge: VIN, 3Vo, GND, the SPI pins SCK, MISO, MOSI, the ESP32's chip select CS, its BUSY line and its reset !RST, then GP0, RXI and TXO. Adafruit's guide wires an UNO this way: SCK, MISO and MOSI to the SPI pins (D13, D12, D11 on the UNO), CS to D10, BUSY to D7, !RST to D5 and GP0 not connected - and so does our demo. BUSY is the handshake: the ESP32 pulls it LOW when it is ready for the next frame and HIGH while it is selected or working. WiFiNINA waits for LOW before every frame, forever if it has to.

GP0 and TXO: the ESP32's Boot

GP0 is the ESP32's GPIO0, a boot strap. Left open, the ESP32 starts its firmware. Held LOW when the reset ends, the ESP32's ROM enters its download mode and waits for new firmware on its UART - no NINA, no answers on SPI. TXO is that UART's output: after every reset the ROM prints a few lines at 115200 baud. Our model does both, so you can see why a breakout with GP0 tied low never answers.

Features of the AirLift ESP32 Breakout Library for Proteus

  • The AirLift breakout as it looks: the black board at its real size with the ESP32-WROOM-32 module, its antenna, the three small LEDs, the regulator, the level shifter, two mounting holes and the 12-pin header with its names.
  • The real WiFiNINA library: our model answers the NINA commands exactly as the library expects - we ran the library and the demo sketch unchanged against the model on the PC (29 checks) and in Proteus.
  • The BUSY handshake, reset and boot as on the real breakout, and GP0 as the boot strap: LOW at reset gives the ROM's download mode.
  • TXO with the ROM's boot text at 115200 baud, and 3Vo HIGH while the breakout is powered.
  • Wi-Fi and sockets: join, status, IP, RSSI, scan, DNS, ping and the time; ten sockets for WiFiClient, WiFiSSLClient, WiFiServer and WiFiUDP.
  • The red, green and blue LEDs, each as bright as WiFi.setLEDs() says, and an antenna that turns green on Wi-Fi and orange while it sends.
  • Wi-Fi in Proteus: a virtual router with DHCP and two neighbours for scans, a phone in the panel, an internet host with a small cloud for updates, and TCP / UDP to every TEP Wi-Fi part in the design.
  • Our Laptop and Mobile WiFi Monitors: a laptop and a phone on the same network, with a browser, TCP terminals and ping - included in the package.
  • Our pop-up panel: the phone, the breakout card, an SPI page with every WiFiNINA command, the sockets and the boot state, a Test page, Settings and Help.
  • A compact package: about 2.70 MB, without the C++ source code of the models.

The AirLift ESP32 Breakout in Proteus

Figure: The part as the library draws it: the ESP32-WROOM-32 with its antenna, the R, G and B LEDs, the PWR and SPI LEDs, the PANEL pad, the regulator, the 74AHC125 and the header VIN, 3Vo, GND, SCK, MISO, MOSI, CS, BUSY, !RST, GP0, RXI, TXO.

Search AIRLIFT in Pick Devices; the device AIRLIFT ESP32 BREAKOUT is in TEPAIRLIFTBO.LIB. Its pins point down from the header like the pins of the real board. In Proteus the !RST pin is named RST. Click the PANEL pad or the ESP32 module to open the panel.

Figure: The breakout placed in a design, before Run: all LEDs off, the antenna quiet.

Every State of the AirLift ESP32 Breakout

We ran the demo and paused the simulation for each picture. At Run the breakout gets its supply and the ESP32 starts; the UNO's first WiFiNINA call resets it with D5 and waits for BUSY to go LOW:

Figure: Booting: the red PWR LED on, the ESP32 starting its firmware.
Figure: Joining: the sketch set the red LED dim and called WiFi.begin(); the orange SPI LED shows the commands.
Figure: An upload: the sketch switches the blue LED on while the HTTPS request goes out; the antenna is orange while the ESP32 sends.
Figure: On Wi-Fi, between uploads: the green LED dim and the antenna green.
Figure: The panel's phone asked for the page: the antenna orange while the ESP32 sends it back.
Figure: OUT OF RANGE: the router is gone, the antenna quiet; the sketch noticed and joins again with the red LED dim.
Figure: GP0 tied to ground: the ROM's download mode. Only PWR is on; the SPI LED stays dark because the ESP32 never answers.

Download AirLift ESP32 Breakout Library for Proteus

Click the button below to download AirLift-ESP32-Breakout-Library-for-Proteus-v1.0.zip (about 2.70 MB, without the C++ source code of the models):

AirLift ESP32 Breakout Library for Proteus V1.0
  • README.txt: the device, installation, the demo, the pins, the properties, troubleshooting and the limits.
  • Proteus Library Files: TEPAIRLIFTBO.LIB (the breakout), ArduinoV4TEP.LIB (our Arduino boards V4.0 - the UNO of the demo), TEPLAPTOP.LIB and TEPMOBILE.LIB (our Laptop and Mobile WiFi Monitors).
  • Proteus Model Files: TEPNET.DLL (the breakout, the two monitors and the Wi-Fi network) and TEPARDUINO.DLL (the Arduino boards).
  • Proteus Simulation: the demo project, its HEX file and copies of the DLLs.
  • Arduino Code: the demo sketch. WiFiNINA is not included - install "WiFiNINA - Adafruit Fork" from the Library Manager.

No Proteus yet? Read How to Download and Install Proteus 7 and 8. New to libraries? Follow How to Install a New Library in Proteus.

How to Install AirLift ESP32 Breakout Library for Proteus

  1. Close Proteus and extract the whole zip file, for example to your Desktop.
  2. Copy the four files from Proteus Library Files into the LIBRARY folder of Proteus (usually C:\Program Files (x86)\Labcenter Electronics\Proteus 8 Professional\LIBRARY).
  3. Copy TEPNET.DLL and TEPARDUINO.DLL from Proteus Model Files into the MODELS folder - replace older copies (this TEPNET.DLL is the first one that knows the breakout, and it still runs the AirLift shield, all our ESP32 boards, the ESP8266 and ESP32 modules and the two monitors).
  4. Delete TEPAIRLIFTBO.IDX, ArduinoV4TEP.IDX, TEPLAPTOP.IDX and TEPMOBILE.IDX from the LIBRARY folder if they are there.
  5. Start Proteus, press P and search for AIRLIFT.

The sketch is a normal UNO sketch: select Arduino Uno in the Arduino IDE, install the Adafruit WiFiNINA, write your sketch and use Sketch > Export Compiled Binary; then double-click the UNO in Proteus and set its Program File to the HEX (see How to get the HEX file from Arduino).

Demo: A Cloud Logger with the Laptop and the Phone

Open AirLift-ESP32-Breakout-Cloud-Logger-with-Laptop-and-Mobile.pdsprj. On the left is our Arduino UNO Library for Proteus V4.0 (ARD1) with its built-in serial monitor and a pot on A0, in the middle the AirLift breakout (U1), and on the right the laptop (PC1) and the phone (MOB1) - no wires to them, they are on the TEP-WiFi network like the real ones.

Figure: The whole demo: the titles, ARD1 with RV1 on A0, U1 the AirLift breakout, PC1 the Laptop WiFi Monitor and MOB1 the Mobile WiFi Monitor.

Six net labels join the UNO and the breakout: SCK, MISO, MOSI (D13, D12, D11), ESP_CS (D10), ESP_BUSY (D7) and ESP_RST (D5). VIN goes to VCC and GND to ground; GP0, 3Vo, RXI and TXO stay open. RV1 (10k, at 35 %) on A0 gives the value the sketch uploads:

Figure: The UNO and the breakout: the six labels from D13, D12, D11, D10, D7 and D5 to the breakout's pins, VIN and GND.

The two tools come from our Laptop WiFi Monitor Library for Proteus and Mobile WiFi Monitor Library for Proteus. In this project their browsers open http://192.168.1.101/; you only press Go. The laptop is 192.168.1.21 and the phone 192.168.1.41:

Figure: PC1 on the sheet: its browser on the breakout's status page.
Figure: MOB1 on the sheet: the same page in its browser.

The Sketch: WiFiNINA on the AirLift Breakout

Adafruit's WiFiNINA needs to know where the breakout is wired. The sketch names the pins and passes them to WiFi.setPins() before any other WiFi call; GP0 is -1 (not connected). WL_NO_MODULE means the ESP32 did not answer:

#define SPIWIFI       SPI                                          // the breakout's wires (WiFi.setPins)
#define SPIWIFI_SS    10
#define SPIWIFI_ACK   7
#define ESP32_RESETN  5
#define ESP32_GPIO0   -1
  WiFi.setPins(SPIWIFI_SS, SPIWIFI_ACK, ESP32_RESETN, ESP32_GPIO0, &SPIWIFI);
  if (WiFi.status() == WL_NO_MODULE) {
    Serial.println(F("No AirLift found - check CS D10, BUSY D7, !RST D5, SPI and GP0 (open)"));
    while (true) delay(1000);
  }

WiFi.begin() waits five seconds before it asks for the status - on the real breakout too - so the join takes a little over five seconds. Then the sketch asks the ESP32 for the time. WiFi.getTime() gives the seconds since 1970 once the ESP32 has heard from a time server (0 before that), so the sketch tries a few times and keeps the answer with millis():

void syncTime() {
  unsigned long t = 0;
  for (int i = 0; i < 10 && !t; i++) { t = WiFi.getTime(); if (!t) delay(500); }
  if (!t) { Serial.println(F("Time: not yet (WiFi.getTime() = 0)")); return; }
  epochAt = t; millisAt = millis();

DNS and ping are one call each; both block until the ESP32 has the answer, and BUSY stays HIGH meanwhile:

void pingCloud() {
  IPAddress ip;
  if (!WiFi.hostByName(host, ip)) { Serial.println(F("DNS: no answer")); return; }
  Serial.print(F("DNS: ")); Serial.print(host); Serial.print(F(" = ")); Serial.println(ip);
  const int ms = WiFi.ping(ip);
  Serial.print(F("Ping: ")); Serial.print(ms); Serial.println(ms >= 0 ? F(" ms") : F(" (no answer)"));
}

The HTTPS Upload

Every 20 seconds the sketch sends the pot and the RSSI to iot.example.com, the cloud of our virtual internet host. WiFiSSLClient is a WiFiClient that asks the ESP32 for a TLS socket; the request is a plain HTTP GET with an api_key and two fields:

  if (!cloud.connect(host, 443)) {
  snprintf(msg, sizeof msg, "GET /update?api_key=%s&field1=%d&field2=%ld HTTP/1.1\r\n", apiKey, pot, rssi);
  cloud.print(msg);
  sendP(cloud, F("Host: iot.example.com\r\nConnection: close\r\n\r\n"));

The answer is an HTTP header and a number: the stored entry, or 0 when the same key sent an update less than 15 seconds ago. The sketch skips the header up to the blank line and reads the number:

  while ((cloud.connected() || cloud.available()) && millis() - t0 < 5000) {   // skip the headers, read the number
    if (!cloud.available()) continue;
    const char ch = cloud.read();
    if (!body) { if (ch == '\n') { if (++blank == 2) body = true; } else if (ch != '\r') blank = 0; continue; }
    if (ch >= '0' && ch <= '9') answer = (answer < 0 ? 0 : answer * 10) + (ch - '0');
  }
  if (answer > 0) {
    stored++;
    memmove(&recent[1], &recent[0], 2 * sizeof(Upload));
    recent[0].at = now(); recent[0].entry = answer; recent[0].pot = pot;
    snprintf(msg, sizeof msg, "entry %ld stored - pot %d, RSSI %ld dBm (%lu ms)", answer, pot, rssi, ms);
  } else if (answer == 0) {
    refused++;
    snprintf(msg, sizeof msg, "answer 0 - refused (one update per 15 s)");
  } else {
    failed++;
    snprintf(msg, sizeof msg, "no answer");
  }

The breakout's LEDs belong to the ESP32, and the sketch uses them for its state: red while it joins, green on Wi-Fi and blue while an upload runs:

  WiFi.setLEDs(0, 0, 80);                                          // blue: uploading

Press Run and watch the UNO's monitor: the firmware version, the join, the page address, the time, the cloud's address, a ping and the first upload:

Figure: The UNO's monitor at 9600 baud: the AirLift found with firmware 1.7.4, joined to TEP-WiFi, the time from WiFi.getTime(), iot.example.com resolved and pinged, entry 1 stored.
AirLift Cloud Logger - The Engineering Projects
AirLift firmware 1.7.4
Joining TEP-WiFi... connected
Status page: http://192.168.1.101/
Signal: RSSI -46 dBm
Time: 2026-10-20 22:51:15 UTC (WiFi.getTime)
DNS: iot.example.com = 203.0.113.10
Ping: 60 ms
[22:51:15] cloud: entry 1 stored - pot 358, RSSI -46 dBm (343 ms)

The request on port 443 takes about a third of a second: the connection to the internet host, the request, the answer and the close. The time is UTC; the panel's phone shows the same clock in your PC's time zone.

The Status Page

In the laptop's Browser the address bar already holds http://192.168.1.101/ - click Go. The page shows the time, the pot, the RSSI, the uploads so far and the last three entries, with two links:

Figure: http://192.168.1.101/ on the laptop: the time, the pot (A0), the RSSI, the cloud counters, entry 1, UPLOAD NOW and REFRESH.

The page is built line by line from RAM. A short line per value matters on the phone, whose screen is narrow:

  if (lastAnswer == 0) sendP(c, F("<p>Last answer: 0 - wait 15 s</p>\r\n"));
  for (uint8_t i = 0; i < 3 && i < stored; i++) {
    snprintf(msg, sizeof msg, "<p>Entry %ld at %s - pot %d</p>\r\n", recent[i].entry, clockText(t, recent[i].at), recent[i].pot);
    c.print(msg);
  }

UPLOAD NOW asks for /upload, and the sketch uploads before it sends the page back:

  if (!strncmp(req, "GET /upload", 11)) upload();

We clicked it five seconds after an automatic upload, so the cloud refused it - one update per 15 seconds for each key, as many real IoT clouds do. The page says so, and so does the monitor:

Figure: After UPLOAD NOW inside 15 seconds: Cloud: 1 stored, 1 refused, and Last answer: 0 - wait 15 s.
Figure: The UNO's monitor: GET /upload from the laptop, then answer 0 - refused.

On the phone, the same page:

Figure: The status page on the phone, with buttons for a finger.

Seventeen seconds later we tapped UPLOAD NOW on the phone - stored as entry 2:

Figure: The phone after UPLOAD NOW: Cloud: 2 stored, 1 refused, entries 2 and 1.

A little later the automatic upload stored entry 3, and the laptop's REFRESH shows all three:

Figure: REFRESH on the laptop: 3 stored, 1 refused, entries 3, 2 and 1 with their times.
Figure: View source: the HTTP header and the HTML the UNO sent through the breakout.

The UNO's monitor keeps the whole story - the pages, the refused upload, the phone's upload and the automatic ones:

Figure: ARD1's monitor: the page requests, the refused upload, entry 2 from the phone and entry 3 on time.
[22:47:54] cloud: entry 1 stored - pot 358, RSSI -46 dBm (343 ms)
Page: GET / HTTP/1.1
Page: GET / HTTP/1.1
Page: GET /upload HTTP/1.1
[22:47:59] cloud: answer 0 - refused (one update per 15 s)
Page: GET /upload HTTP/1.1
[22:48:16] cloud: entry 2 stored - pot 358, RSSI -47 dBm (372 ms)
[22:48:36] cloud: entry 3 stored - pot 358, RSSI -45 dBm (385 ms)
Page: GET / HTTP/1.1

The loop that does it is short:

  if (millis() - lastUpload >= UPLOAD_EVERY) upload();

The Serial Monitor

The monitor takes commands too: /status, /upload, /time (WiFi.getTime again), /ping (DNS and ping) and /help:

Figure: /status with the cloud counters, /time, /ping with the DNS answer and 81 ms, /help.
/status
IP 192.168.1.101, pot 358, RSSI -47 dBm; cloud 2 stored, 0 refused, 0 failed
/time
Time: 2026-10-20 22:51:42 UTC (WiFi.getTime)
/ping
DNS: iot.example.com = 203.0.113.10
Ping: 81 ms
/help
Monitor: /status, /upload, /time, /ping, /help

The laptop's Network tab can ping the breakout while it works, and the phone's Devices app lists everything on TEP-WiFi:

Figure: The Network tab: the devices on TEP-WiFi and the ping to 192.168.1.101.
Pinging 192.168.1.101:
Reply from 192.168.1.101: bytes=32 time=14ms TTL=255
Reply from 192.168.1.101: bytes=32 time=9ms TTL=255
Reply from 192.168.1.101: bytes=32 time=9ms TTL=255
Reply from 192.168.1.101: bytes=32 time=15ms TTL=255
Packets: sent = 4, received = 4, lost = 0 (0% loss)
Figure: The phone's Devices app: the laptop, this phone, the AirLift U1 at 192.168.1.101 and the panel's phone.

And the whole demo running:

Figure: The demo running: ARD1 and RV1, U1 the AirLift breakout, PC1 and MOB1 with the status page.

The AirLift ESP32 Breakout Panel

The panel opens at Run, in the look of our TEP Serial Monitor Advance for Proteus. Its Wi-Fi page has a small phone of its own and three cards: the BREAKOUT card with the firmware, the MAC address, the host link with its command rate and the LEDs, the WI-FI card and the TRAFFIC card:

Figure: After the set-up: NINA firmware 1.7.4, the MAC address, WiFiNINA on SPI with its command rate, the green LED dim; TRAFFIC with the first upload to iot.example.com.

OPEN ESP32 PAGE asks the breakout for the page the UNO serves; its links work on the phone too. The phone's CLOUD tab lists what the internet host received:

Figure: The panel's phone with the status page.
Figure: The CLOUD tab: U1 /update stored, twice; TRAFFIC shows each connection to iot.example.com.

The SPI page is the place to learn the NINA protocol. It lists the WiFiNINA commands with their requests and answers, newest first - the polls (status, available, connected) are only counted. On the right are the bus, the sockets 0 - 9 and the boot card with GP0 and the last line on TXO:

Figure: An upload on the SPI page: START_CLIENT_TCP to iot.example.com:443 as TLS, SEND_DATA_TCP with the request, GET_DATABUF_TCP with the answer, then SET_PIN_MODE and SET_ANALOG_WRITE for the LEDs.
Figure: After /time and /ping: GET_TIME with the seconds since 1970, REQ_HOST_BY_NAME and GET_HOST_BY_NAME for iot.example.com, PING 81 ms; GP0 HIGH (open) and the ROM's last line on TXO.
Figure: The phone's ROUTER tab: the DHCP clients on TEP-WiFi.

WEAK moves the router far away; the breakout stays connected with a weaker signal:

Figure: WEAK: the signal in orange, still connected.
Figure: /status with the weak signal: RSSI -82 dBm.

OUT OF RANGE takes the router away; WiFi.status() stops saying WL_CONNECTED, so the sketch joins again and is back once GOOD returns the router:

  if (WiFi.status() != WL_CONNECTED) {                              // lost the router: join again
    Serial.println(F("Wi-Fi lost - joining again"));
    WiFi.setLEDs(40, 0, 0);
    while (WiFi.begin(ssid, pass) != WL_CONNECTED) delay(2000);
    WiFi.setLEDs(0, 40, 0);
    Serial.println(F("Back on Wi-Fi"));
  }
Figure: OUT OF RANGE: the card on the phone turns orange, not on Wi-Fi.
Figure: The UNO's monitor: the re-join tests, an upload with the weak signal (RSSI -81 dBm), then OUT OF RANGE - Wi-Fi lost and Back on Wi-Fi.
[22:52:30] cloud: entry 4 stored - pot 358, RSSI -81 dBm (433 ms)
Wi-Fi lost - joining again
Back on Wi-Fi

The Test page measures the running model: the phone opens the page several times, and the router goes out of range for 3 seconds to time the re-join. Then Settings and Help:

Figure: The Test page: three page requests (32 ms each) and three re-joins, measured.
Figure: Settings: TEP Dark or Light, the text size, open the panel at Run, the window size.
Figure: Help: report a bug, suggest a feature, the article, the user guide, updates, donate, the website, the forum; Copy diagnostics.

GP0 LOW: the Download Mode

To see what GP0 does, wire it to ground and press Run again. The ESP32 reads GP0 when its reset ends; LOW means "wait for new firmware", so the NINA firmware never starts. BUSY stays HIGH, and WiFiNINA waits for it in the very first call - the monitor stops after the sketch's first line:

Figure: GP0 LOW: only the sketch's title - WiFi.status() never comes back.

The panel explains it: no command, BUSY HIGH in the download mode, and on TXO the ROM's last line. The ROM prints this text at 115200 baud; a Proteus Virtual Terminal on TXO shows it:

Figure: The SPI page with GP0 LOW: 0 commands, BUSY HIGH - download mode (GP0 LOW), TXO waiting for download.
ets Jun  8 2016 00:22:57

rst:0x1 (POWERON_RESET),boot:0x3 (DOWNLOAD_BOOT(UART0/UART1/SDIO_REI_REO_V2))
waiting for download

Leave GP0 open (Adafruit's guide does) and the ESP32 boots normally; its ROM prints the normal boot lines on TXO and the NINA firmware starts. GP0 matters on the real board only for Bluetooth and firmware updates.

Pins of the AirLift ESP32 Breakout

The Proteus pins of the AirLift ESP32 Breakout
PinIn the demoWhat it does
VINVCCthe supply, 3.3 - 5 V - without it the breakout is off
3Voopenthe regulator's 3.3 V output (HIGH while powered)
GNDgroundground
SCKD13the SPI clock
MISOD12data to the UNO; floats while CS is HIGH
MOSID11data from the UNO
CSD10the ESP32's chip select (LOW = selected)
BUSYD7the ESP32's READY / BUSY line: LOW = ready for the next frame
!RSTD5the ESP32's reset: LOW = reset, open = running
GP0openthe boot strap: LOW at reset = the download mode
RXIopenUART0 in (not used by the model)
TXOopenUART0 out: the ROM's boot text at 115200 baud

Properties of the AirLift ESP32 Breakout

Double-click the breakout to change them; every run starts again from the properties
PropertyWhat it does
WIFISSID / WIFIPASSthe router in range (TEP-WiFi / 12345678)
FIRMWAREthe NINA version WiFi.firmwareVersion() reports (1.7.4)
PANELthe phone's tab at start (BROWSER, ROUTER, CLOUD)
PAGEPORTthe port OPEN ESP32 PAGE opens (80)
CLOCKthe time WiFi.getTime() gives: PC or a fixed start time

The IP address follows the part's number: U1 gets 192.168.1.101, U2 .102 and so on, so give every Wi-Fi part its own number. The laptop is always 192.168.1.21 and the phone 192.168.1.41.

Troubleshooting

  • "No AirLift found" (WL_NO_MODULE): check CS, BUSY, !RST, SCK / MISO / MOSI and VIN / GND, and call WiFi.setPins() with your pins before anything else.
  • The sketch hangs at the first WiFi call: BUSY never goes LOW - no power, !RST held LOW, or GP0 LOW (the panel's SPI page says which).
  • WiFi.begin() takes five seconds or more: WiFiNINA waits five seconds before it asks for the status.
  • "answer 0" from the cloud: the internet host keeps one update per 15 seconds for each api_key.
  • Slow pages: send whole lines from RAM, not print(F("...")) - see sendP() in the demo.
  • No panel: click the PANEL pad or the ESP32 module, or turn "Open the panel at Run" back on in Settings.

Things to Know Before Using a Real AirLift Breakout

  • The library: install "WiFiNINA - Adafruit Fork"; Arduino's own WiFiNINA does not have setPins() and setLEDs().
  • The supply: feed VIN from 5 V even on a 3.3 V board - Wi-Fi needs up to 250 mA peaks.
  • Any SPI board: the breakout is level-shifted, so it works with 3.3 V and 5 V boards; use the board's hardware SPI pins and any free pins for CS, BUSY and !RST.
  • A shared bus: MISO is tri-stated while CS is HIGH, so other SPI devices can share the bus.
  • RAM: an UNO has 2 KB; WiFiNINA, its socket buffers and a few strings fill it quickly - keep text in flash.
  • TLS: the real NINA firmware checks the server's certificate; a server whose certificate it does not trust fails to connect.

Limitations of the Simulation

  • The ESP32 runs our model of the NINA firmware as WiFiNINA (Adafruit 1.6.x) uses it - not the real firmware.
  • Not modelled: the access point mode (WiFi.beginAP() answers WL_AP_FAILED), WEP and WPA2-Enterprise (joined as WPA2), real TLS (WiFiSSLClient connects as plain TCP to the internet host on port 443), Bluetooth and firmware updates on RXI, the ESP32's other GPIOs, the supply's voltage and current, the radio itself - the join and network times are realistic values, not a radio simulation.
  • The internet host is a stand-in for the internet: every internet name is 203.0.113.10, and its small cloud stores updates with an api_key and fields.
  • The PWR and SPI LEDs, the antenna colours, the PANEL pad, the panel, its phone, the router, the two neighbour networks, the internet host and the two monitors are TEP additions.
  • Adafruit and AirLift are names of Adafruit Industries, ESP32 and ESP32-WROOM-32 of Espressif Systems; this library is not made or endorsed by Adafruit, Espressif, Arduino or Labcenter.
  • Tested in Proteus 8.5 in October 2026 (the demo as shipped, the UNO, the breakout, the laptop and the phone together at about 0.4 to 0.5 x real time on our PC). Proteus 7 is not supported.

So, that was all about the AirLift ESP32 Breakout Library for Proteus. I hope it helps you try WiFiNINA sketches in Proteus before you wire the real breakout - the time, DNS, HTTPS and the boot pins included - and watch every SPI command on the panel while you do. The Laptop and Mobile WiFi Monitors talk to every one of our Wi-Fi boards and modules. If you use the AirLift ESP32 Breakout Library for Proteus in a project, please share it in the comments or in our forum, and if you have any questions, ask in the comments and I will help you out. Till the next tutorial, take care and have fun!