Unofficial guide to the WT32-ETH01 (and WT32-ETH02, WT32-ETH01-EVO, and assorted clones)
The WT32-ETH01 is effectively a small, cheap ESP32 development board with Ethernet, WiFi, and GPIO pins, made by a company called "Wireless-Tag" (WT). As of this writing, it's around $17 at Amazon and around $2.33 from AliExpress.
There aren't a ton of ESP32 boards with Ethernet, and the WT32-ETH01 is by far the smallest, cheapest, and simplest. (The OLIMEX ESP32-POE and wESP32 are the other notable options.) So, if you want a cheap-and-cheerful ESP32 board with the reliability of a wired network, the WT32-ETH01 may be a good choice.
It's marketed as a "serial port to Ethernet module" and comes loaded with firmware that lets you send various "AT" commands over 3.3V serial to set up networking, open connections and exchange data. For most of us, it's more interesting to just flash our own programs on the unit and use standard ESP32 networking libraries.
Nobody knows much about the WT company. Don't expect support, and don't lock yourself in too much, but they do describe Board Features and Board Resources.
Also, see Luberth Dijkman's notes on the part.
WT sells several boards under similar names, and it took some digging (thanks owenthewizard for prompting the investigation!) to untangle what is actually what. Here is the best information I have, gleaned from the official datasheets:
| WT32-ETH01 (original) | WT32-ETH02 / -PLUS | WT32-ETH01-EVO | |
|---|---|---|---|
| SoC module | WT32-S1, ESP32-D0WD-V3 — dual-core Xtensa | ESP32-SOLO-1 (ESP32-S0WD) — single-core Xtensa | WT32C3-S5, ESP32-C3 — single-core RISC-V |
| Max clock | 240 MHz | 160 MHz | 160 MHz |
| Flash | 4 MB | 16 MB (128 Mbit per datasheet) | 4 MB (typical for the ESP32-C3 module) |
| WiFi / BT | 2.4 GHz WiFi + Bluetooth classic+LE | 2.4 GHz WiFi + Bluetooth classic+LE | 2.4 GHz WiFi + Bluetooth LE only |
| Ethernet | LAN8720A PHY via RMII, using ESP32's built-in MAC | LAN8720A PHY via RMII (same as ETH01) | DM9051NP MAC+PHY via SPI (the ESP32-C3 has no built-in EMAC) |
| Power | 3.3V or 5V (no PoE) | 3.3V or 5V; the -PLUS variant adds an IEEE 802.3af PoE module on the bottom | 3.3V or 5V; reserved PoE pads, needs external step-down for full PoE |
| Pinout | original 2×13 layout (see Pins below) | same layout and GPIOs as ETH01 — pin-compatible | different 2×15 layout, fewer GPIOs exposed |
| Datasheet | V1.4 PDF | V1.0 PDF | V2.0 PDF |
A few things to flag:
- DM9051NP vs W5500: the DM9051NP is not a hardware TCP/IP stack like the W5500. It's a plain SPI-attached Ethernet MAC+PHY (closer in spirit to the ENC28J60) with 16KB packet RAM and IP/TCP/UDP checksum offload, but no on-chip socket engine. The host CPU still runs the TCP/IP stack (lwIP, in ESP-IDF's case). It's supported natively by ESP-IDF as a SPI Ethernet module.
- WT32-ETH02 vs WT32-ETH02-PLUS: as best I can tell, the PLUS is the same board with an add-on PoE module soldered to pads underneath. Often sold as a kit with an "ETH Adapter Board" for USB programming (see Programming below).
- WT32-ETH01-EVO is a different beast: despite the name, it's not a drop-in upgrade. Different SoC family (RISC-V instead of Xtensa), different Ethernet chip (SPI instead of RMII), and a different pinout — so neither the software setup nor a carrier-board design will transfer.
- "ESP32-ETH02" (with "ESP" instead of "WT") boards are widely sold on AliExpress and Amazon. Per a tip from owenthewizard, these are counterfeits/clones of the WT32-ETH02 and reportedly less reliable. Caveat emptor.
The ETH01 and ETH02 use the same 2×13 header layout with the same ESP32 GPIO numbers in the same positions — so a carrier board designed for the ETH01 should accept an ETH02. The silkscreen on the ETH02 labels some pins by their AT-firmware function (CFG = IO32, 485_EN = IO33, RXD = IO5, TXD = IO17, TXD0 = IO1, RXD0 = IO3) rather than the GPIO number, but the actual signals match. The full diagram in Pins (and gotchas!) below applies to both.
The ETH01-EVO uses a different 2×15 header layout. Only eight ESP32-C3 GPIOs are broken out (IO0, IO1, IO2, IO4, IO5, IO9, IO18, IO19) — a much smaller selection than the ETH01/02, since the C3 only has 22 GPIOs total and the DM9051 SPI bus, flash, and USB-JTAG take up most of the rest. Strapping rules are also completely different from the ESP32: IO9 is the boot-mode pin (the C3's equivalent of IO0 on the ESP32), IO2 and IO8 are also strapping pins, and there's no ADC2-vs-WiFi conflict to worry about. The two extra pin positions at the bottom of the EVO are POE+/POE- for an external PoE step-down module. Consult the EVO datasheet and the ESP32-C3 pin reference for details.
The rest of this document describes the original WT32-ETH01 except where noted. If you have hands-on experience with the ETH02 or EVO, please file an issue — I'd love to fold in real-world notes.
Pinout for the WT32-ETH01/02 (not EVO!)
| EN ⏻ | WT32-ETH01 (ESP32) |
⭕ IO1 (reserved) | 💬 TXD | |
| GND ⏚ | ⭕ IO3 (reserved) | 🗨️ RXD | ||
| 3.3V ⚡ | ⭕ IO0 (reserved) | ⏱️ REFCLK / 💻 BOOT | ||
| low to reset | EN ⏻ | ⏚ GND | ||
| ADC1 CH4 📈 | IO32 | ⬅️ IO39 (in only) | 📈 ADC1 CH3 | |
| ADC1 CH5 📈 | IO33 | ⬅️ IO36 (in only) | 📈 ADC1 CH0 | |
| IO5 | 📉 ADC2 CH3 | |||
| IO17 | 📉 ADC2 CH6 | |||
| GND ⏚ | ||||
| 3.3V ⚡ | ⬅️ IO35 (in only, no pull) | 📈 ADC1 CH7 | ||
| GND ⏚ | 📉 ADC2 CH0 | |||
| 5V ⚡ | ||||
| eth status | LINK 🖧 | ⏚ GND |
LEGEND
⭕ - Not recommended for application use
⬅️ - Input only, no internal pullup/pulldown
📈 - Analog input on ADC1
📉 - Analog input on ADC2 (conflicts with wi-fi)
Also see the data sheet/manual and pin reference for the ESP32 itself.
Some documents (like this listing) have pins IO5 and IO35 swapped in comparison to the layout above. All the physical hardware I've seen has the pins laid out as above, but check to make sure!
There are limitations on several of the pins; see "Strapping Pins" (section 3.3) in the processor data sheet.
-
IO0: At boot, must be pulled low to program, must float or be pulled high to boot normally. After booting, used to receive the Ethernet 50Mhz clock (enabled by IO16). Best to avoid any other use.
-
IO1: ESP32 serial output. Used when programming and active by default when running. Best to avoid any other use.
-
IO2: At boot, must float or be pulled low to program. You can use this pin (especially for output) but make sure nothing pulls it high while booting.
-
IO3: ESP32 serial input. Used when programming and active by default when running. Best to avoid any other use.
-
IO5, IO15 (MTDO): At boot, IO5 controls whether ESP32 libraries print debug messages to serial (IO1). Also at boot, IO5 and IO15 together control SD card emulation timings (you probably don't care). You can use these pins (especially for output) but note the effects if pulled while booting.
-
IO12 (MTDI): At boot, must float or be pulled low or the chip won't work (wrong voltage). You can use this pin (especially for output) after booting, but make sure nothing pulls it high while booting.
-
IO35, IO36, IO39: These pins are input only and have no internal pullup/pulldown support, but are otherwise free to use.
The WT32-ETH01 board is 60mm x 26mm x 17mm, and weighs 15.4g. (Thanks damdo!)
This repository includes a KiCad symbol and footprint. The symbol is arranged by actual physical pin number (rather than grouped by pin type) to make it easier to design circuits with few overlapping traces. I tried to be as descriptive as possible, but ESP32 pins all have many functions so consult other general ESP32 documentation for additional information about the pins. Note that some of the pin labels differ from what is on the board itself; the marks on the board indicate uses for the built-in firmware, which you will almost certainly replace. I made these from sporadic documentation (most of which is linked to in this repo!) but they have been tested in my own projects so I have some confidence. Obviously they are provided with no warranty. Caveat emptor. (Thanks dakotawinslow and mcenno!)
You can also find 3D models in STEP and WRL formats. (Thanks oliv3r!)
You may supply 3.3V power on the 3V3 pins, or 5V power on the 5V pins, but not both at once!
The schematic lists an "LM1117F-1.8V" voltage regulator, which is clearly wrong-- the output is 3.3V, not 1.8V, and also the actual part on the board is marked "AMS1117-3.3". If this were a true AMS1117 it would have a max input of 15V and thermal protection, but it doesn't actually seem to have either; with 12V input, many WT32-ETH01 parts will generate smoke. Probably it's a low-spec AMS1117 knock-off of some kind. So, I'd limit its input to 6V or so, or use your own 3.3V source if you need to.
The WT32-ETH01 does not support Power over Ethernet (PoE), you'll need an external "splitter" if you want that, or use the WT32-ETH02-PLUS.
The WT32-S1 module (silver box) includes an R-C circuit on EN with 10KΩ × 0.1µF = 1msec time constant. The WT32-ETH01 board includes a separate R-C circuit for the LAN8720A Ethernet controller, also with 1msec time constant. These are quite fast, so if input voltage ramps slowly, the chip may not start reliably, as discussed in this thread.
This can be fixed if necessary by adding another capacitor (e.g. 10µF for 100msec of reset delay), a proper reset supervisor, or a power supply/regulator with a PGOOD (or /RESET) signal you can tie to EN.
Astute readers will have noticed this part has no USB port, so you need an adapter of some kind. There are several possibilities, listed below; whichever one you use, PlatformIO's WT32-ETH01 board support or the Arduino IDE ESP32 add-on (selecting ESP32 Dev Board and upload speed of 115200) should work for programming, or you can use esptool.py directly if you're hardcore. (I'm not that hardcore.)
(Thanks owenthewizard!)
The WT32-ETH02 and WT32-ETH01-EVO are often bundled with an "ETH Adapter Board" (visible in AliExpress listings like these) — a small PCB with a USB-C port plus RST and BOOT buttons, with female headers that mate with the top headers on a pre-soldered ETH02/EVO board. I have not used one, but based on pictures it has a CH340C USB-serial bridge and the usual dual-transistor bootloading circuit, so it should work nicely. (No public schematic that I've been able to find; if you have one, please share!)
One convenient programming solution is a gizmo like M5Stack's ESP32 Downloader (I use this) or wESP32-Prog (untested, but ought to work). These products include a USB-serial adapter and an automatic bootloading circuit. They have 6 pins (in different orders, sadly) that connect to the 6 "programming" pins at the top (WiFi antenna end) of the WT32-ETH01, at which point programming should work. When I design carrier boards for the WT32-ETH01, I route those 6 pins to a 6-pin header laid out for the programmer. If you're working with a raw board, you can use jumper wires like these.
When wiring up the gizmo, make sure gizmo RX goes to WT32-ETH01 TX and vice versa. Also mind the power connections; the M5Stack programmer has a 3.3V output, the wESP32-Prog has a 5V output, make sure you use the right power pin if you want the programmer to power the board. (The 5V input isn't actually in the top 6 "programming pins", but it is labeled.)
You can also program the WT32-ETH01 with a regular USB-serial adapter, but it is a bit tricky:
- You need a 3.3V TTL adapter, not 5V (and certainly not RS-232!)
- To load code, the ESP32 needs the IO0 (BOOT) pin grounded while toggling EN
- You can manually connect those pins to ground (with wires, or buttons) but this gets old fast
- Or, use automatic DTR/RTS bootloading, which needs this mini circuit:
(Thanks cyberboy666!)
When wiring up a serial adapter, make sure adapter RX goes to WT32-ETH01 TX and vice versa. You will also need to power the WT32-ETH01 somehow, of course.
(Thanks comporder1!)
If you don't have a downloader gizmo or serial adapter, but do have an Arduino Uno or similar with onboard USB-serial, you can use it. Remove the Arduino microcontroller IC, then use four wires to link 3v3, GND, TX, and RX between the Arduino and WT32-ETH01. (Do NOT cross TX/RX with this method.) You will need to manually connect IO0 (BOOT) to ground while powering on the WT32-ETH01 to put it in bootloader mode, but then programming should work.
WiFi is internal to the ESP32 and works "out of the box", but wired Ethernet takes a bit of configuration for the WT32-ETH01:
- The interface to the Ethernet PHY uses GPIO 23 for MDC and GPIO 18 for MDIO
- There's an external oscillator that drives pin 0
- That oscillator is enabled by setting GPIO 16 high
- The PHY reset pin is NOT wired to a GPIO (it gets reset at startup)
(Thanks ProgrammingJohn and EchterAgo!)
The ETH library that comes with the ESP32 Arduino runtime should work if started like this:
#if ESP_ARDUINO_VERSION_MAJOR >= 3
// The argument order changed in esp32-arduino v3+
ETH.begin(ETH_PHY_LAN8720, 1, 23, 18, 16, ETH_CLOCK_GPIO0_IN);
#else
ETH.begin(1, 16, 23, 18, ETH_PHY_LAN8720, ETH_CLOCK_GPIO0_IN);
#endif
(Note that pin 16 is being configured as PHY reset, even though it's not actually the reset pin, this will cause the library code to set it high which is needed to enable the oscillator.) This will initialize the ESP-IDF lwIP subsystem, and most Arduino networking code should work.
If you're not using the Arduino runtime, or don't like the ETH library, or want finer control, you can use ESP-IDF interfaces directly. As above, this will initialize lwIP, so again most networking code should work.
#include <esp_netif.h>
#include <esp_netif_types.h>
...
// https://esphome.io/components/ethernet.html
ESP_LOGD(TAG, "Initializing Ethernet MAC for WirelessTag WT32-ETH01...");
eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG();
mac_config.clock_config.rmii.clock_mode = EMAC_CLK_EXT_IN;
mac_config.clock_config.rmii.clock_gpio = EMAC_CLK_IN_GPIO;
mac_config.smi_mdc_gpio_num = 23;
mac_config.smi_mdio_gpio_num = 18;
mac_config.sw_reset_timeout_ms = 1000; // from ETH.cpp
mac = esp_eth_mac_new_esp32(&mac_config);
ESP_LOGD(TAG, "Initializing Ethernet PHY (LAN8720A) for WT32-ETH01...");
eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG();
phy_config.phy_addr = 1;
phy_config.reset_gpio_num = -1;
phy = esp_eth_phy_new_lan87xx(&phy_config);
// Enable external oscillator (pulled down at boot to allow IO0 strapping)
ESP_ERROR_CHECK(gpio_set_direction(GPIO_NUM_16, GPIO_MODE_OUTPUT));
ESP_ERROR_CHECK(gpio_set_level(GPIO_NUM_16, 1));
ESP_LOGD(TAG, "Starting Ethernet interface...");
// Install and start Ethernet driver
esp_eth_config_t eth_config = ETH_DEFAULT_CONFIG(mac, phy);
esp_eth_handle_t eth_handle = nullptr;
ESP_ERROR_CHECK(esp_eth_driver_install(ð_config, ð_handle));
esp_netif_config_t const netif_config = ESP_NETIF_DEFAULT_ETH();
global_netif = esp_netif_new(&netif_config);
auto const eth_netif_glue = esp_eth_new_netif_glue(eth_handle);
ESP_ERROR_CHECK(esp_netif_attach(global_netif, eth_netif_glue));
ESP_ERROR_CHECK(esp_eth_start(eth_handle));
(Thanks marclefevere!)
If you want an EthernetClient-type interface, EthernetESP32 is the library to use. After adding the library:
#include <EthernetESP32.h>
EMACDriver driver(ETH_PHY_LAN8720, ETH_PHY_MDC, ETH_PHY_MDIO, ETH_PHY_POWER);
EthernetClient ethClient;
You can then use things like PubSubClient that use that interface.
(Thanks richo and swgiacomelli!)
If you're so inclined, it's also quite easy to use ESP-IDF from rust:
let sysloop = esp_idf_svc::EspSystemEventLoop::take()?; // Or already have this handle
let clock = esp_idf_svc::eth::RmiiClockConfig::<gpio::Gpio0, gpio::Gpio16, gpio::Gpio17>::Input(
pins.gpio0,
);
let eth_driver = esp_idf_svc::eth::EthDriver::new_rmii(
peripherals.mac,
pins.gpio25, // rxd0
pins.gpio26, // rxd1
pins.gpio27, // crs dv
pins.gpio23, // mdc
pins.gpio22, // txd1
pins.gpio21, // tx en
pins.gpio19, // txd0
pins.gpio18, // mdio
clock,
Some(pins.gpio16), // clock enable (passed as reset as above)
esp_idf_svc::eth::RmiiEthChipset::LAN87XX,
Some(1), // phy addr
sysloop.clone(),
)?;
let eth = esp_idf_svc::eth::EspEth::wrap(eth_driver)?;
let mut eth = esp_idf_svc::eth::BlockingEth::wrap(eth, sysloop.clone())?;
eth.start()?;Alternatively, to avoid using ESP-IDF, check out
ph-esp32-mac driver
which provides a bare-metal (no_std, no_alloc) Rust driver for the
ESP32 Ethernet MAC and LAN8720A PHY used in the WT32-ETH01.
(Thanks mati294 and randompersona1!)
If you're using ESPHome firmware, you'll want to add this to the device configuration:
ethernet:
type: LAN8720
mdc_pin: GPIO23
mdio_pin: GPIO18
clk:
pin: GPIO0
mode: CLK_EXT_IN
phy_addr: 1
power_pin: GPIO16
If you're using Tasmota firmware, use the WT32-ETH01 configuration as documented.
The data sheet/manual gives a pretty good overview of the product, including a system block diagram:
- LAN8720A is the Ethernet physical layer controller (PHY)
- WT32-S1 is WT's ESP32 module (metal box), an ESP32-WROOM-32E-N4 clone based on the ESP32-D0WD-V3 chip (dual-core Xtensa, now NRND), with 4MB (32Mb) of flash and no PSRAM
- "Left Interface" and "Right Interface" are just the two pin headers
- "烧录接口" means "programming interface" (the six topmost pins)
There are multiple revisions of the device -- I've seen "V1.2" and "V1.4" on the silkscreen, and the trace routing does differ -- but the differences are unknown. You can get it with or without pin headers pre-soldered on.
Finally, WT hosts a page of resources including a schematic which has been helpful to me.
- Post KiCad files for
footprints, breakout boards, and programming connectors



