Adding WIFI the Easy Way
If you start from scratch, the best thing is to buy a board with integrated WIFI. But this is not possible in all cases. Many older boards just don't have a suitable chip. This is especially true for boards that are based on the RP2040.
For example I recently bought the TinyFX from Pimoroni. That is a very small board about the size of a Qt-Py for controlling Lego lighting kits:

Another example is the Tufty2040, a large sized display with a RP2040 on board:

But I have also quite a few other boards lying around that would profit from connectivity e.g. the ItsyBitsy M4 Express. And of course I also own some of the shiny new Pico2 boards.
Airlift
The standard solution for adding WIFI is Airlift. Airlift is a WIFI-coprocessor running a special firmware on an Espressif ESP32-WROOM-32. Besides the "pure" chip on a breakout, there are also addons for specific form-factors like a FeatherWing or a BitsyWing.
But Airlift has two major problems. The first is wiring. Airlift is based on SPI and in addition uses a number of control GPIOs. So if you don't use one of the wings (that block all of your pins) you end up with wiring 7-9 jumper-cables. That is not only cumbersome, but the boards above don't even provide that many pins (the TinyFx e.g. just exposes what you see in the image).
The second problem is software. The Airlift uses a special
CircuitPython library
that does it's job, but in a slightly different way than the standard
WIFI support of CircuitPython does. E.g. instead of connecting with
wifi.radio.connect() you use esp.connect_AP() and instead of using
wifi.radio.connected you check the connection state with
esp.is_connected. There are many other differences in the API. So all
the boilerplate code you have or download from the internet has to be
adapted for the Airlift. As long as this is your main code.py file,
this is no major problem. But once you start using libraries things get
complicated. You have to install the source version of the libs and
adapt them. Maintaining this is no fun.
ESP-AT
An alternative to Airlift is ESP-AT. This is a firmware maintained and provided by Espressif turning many of their chips into WIFI-coprocessors. ESP-AT is highly customizable but in its standard versions it uses plain UART for the communication with the main MCU. So you basically only need four wires: VCC, GND, RX and TX.
The drawback of ESP-AT is its textual interface: you send so called "AT-commands" to the co-processor and then you have to parse the response to extract the relevant data. Some of these commands are really complicated, e.g. to connect to an AP you would send
AT+CWJAP="myssid","mypasswd",,0,1,3,1,5,1
Wrapping all the complexity in a library really makes sense. For this reason, Adafruit had created the library CircuitPythonESPAT_Control, but it was abandoned in favor of Airlift and is no longer maintained. That library also suffers from the same drawback as the Airlift library, i.e. it uses a different API than standard CircuitPython.
CircuitPython-ESP32AT
For this reason I created a new library called
CircuitPython-ESP32AT. This
library talks to the ESP-AT on an ESP-coprocessor, but instead of
inventing yet another API it uses the standard CircuitPython API for
wifi, ssl, socketpool and so on.
At first, this might seem confusing. On boards with native WIFI these modules don't need to be installed, since the CircuitPython firmware already provides them. For other boards, the ESP32AT project now provides drop-in modules with the same names providing (almost) the same set of functionality.
One important function the external modules don't provide is the web-workflow which really needs native WIFI. Otherwise, you need to look hard to spot differences.
You will find installation and setup instructions as well as notes about various hardware alternatives in the repo of the library. Instead of reproducing this information here, I only show some examples I actually use.
Hardware
From hardware side, you need a board with a supported ESP-chip. Any ESP32, ESP32-S2 and ESP32-Cx will do. ESP32-S3 and the ESP32-Hx series are not supported. You can even use very old ESP8266 hardware as long as it has 1MB of flash. But this is not really recommended since the ESP8266 only supports operation in TCP/UDP/SSL client mode. In addition, you have to compile the firmware yourself (which in fact is easy and a matter of a quarter of an hour - see the repo for details).
Wiring is easy: you must connect RX/TX of your host MCU to the AT-UART ports TX/RX of the coprocessor. Besides RX/TX you should also connect GND. Powering the coprocessor directly from the host MCU might or might not work. For example, I had no problems powering the ESP32C3-SuperMini from the 3V3 pin of the Pico/Pico2, but I did not use any other peripherals:

The connection in this image uses a trick: it redefines the I2C-pins of the PiCowbell adapter from I2C to UART. Of course you loose I2C on these pins, so this is not a solution for all problems but it demonstrates how simple wiring can be compared to the Airlift.
I am using the same trick for the TinyFX board from above. The board does not have any dedicated UART-pins, but the pins of the Stemma/Qt can also be repurposed to UART instead of I2C. This allows a very simple connection using a Stemma/Qt-DuPont adapter cable for the connection of the TinyFX to again to an ESP32C3:
Even simpler is the usage together with the Maker Pi Pico Board. This board has a socket designed for the ESP-01S:

Liligo has created a chip with the same form-factor and basically the same pinout, which is called Lilygo T-01 C3. This board works also in the socket and gives full performance and provides all WIFI-functionality.
The Swedish company "iLabs" even has a Feather-sized RP2350 board with an integrated ESP32C6:

Ok, we will see a Pico2-W soon, but until then, this is the best solution for a WIFI-enabled RP2350.
Performance
For most use-cases like updating the time, querying an API (e.g. for weather information) or running an AP with a webserver the performance is just on par with native WIFI. There are some special cases though where native WIFI is better: e.g. I have a high-frequency data-sampling application that sends data using UDP to a reciever. Native WIFI can send with a rate of 0.001s per message, using ESP-AT this is much slower (I measured 0.015s per message).
Also, if you are dealing with large responses the default chunk size
of 32 bytes that the adafruit_requests library uses will slow you
down, since every chunk is an AT-transaction. Using
response.iter_content() directly is a workaround to speed up
processing (this also helps native WIFI a bit and Airlift too).
This page (Adding WIFI the Easy Way) was last updated on November 12, 2024.