Documentation / Hardware

Joining a network

One widget that scans, asks for a password on the panel, and remembers it.

Getting an ESP32 onto WiFi is the same work every time: scan without freezing the screen, show what was found, take a password, say something useful when it fails, and keep the answer so the next boot is silent. WiFi Setup is that work as a single widget. Drop it on a screen and the generator writes the whole flow.

It is on the palette for the Espressif chips only - ESP32, S2, S3 and C3. On an STM32 or an RP2040 the tile is greyed with the reason, because the code behind it is the Arduino WiFi library.

The flow

Search, select, enter pass, verify. Four states, and the password is typed at exactly one of them - on the device, by the person holding it.

StateOn screenLeaves by
Search"Searching…", then the lista scan finishing, or Search again
SelectNetworks strongest first, with a lock where one is neededpicking one
Enter passA masked field and a keyboardthe keyboard's tick, or its cross
Verify"Joining…", then joined, or why notsuccess, or back to the list

An open network skips the middle step: there is nothing to type.

Settings

SettingDefaultWhat it does
TitleSelect networkThe heading above the list.
Go to when joined(none)The screen to move to once it is on the network. Only fires while this screen is the one on show, so a background reconnect does not pull somebody off whatever they were reading.
Go to on Back(none)Puts a Back button on the list. Worth setting: without it the only way off this screen is to join something, which strands anybody who opened it by accident.
Reconnect on bootonRejoins the stored network at startup without asking.
Join timeout20 sHow long to wait before giving up and saying so.
Show ForgetonA button that clears the stored network and starts a fresh scan.
Access pointOffOff, when it cannot join, or always on. See below.

Where the password goes

The widget writes two settings, and your design has to declare them: wifi.ssid and wifi.pass. The second must be marked secret, and the designer says so if it is not.

A secret is different from an ordinary setting in three ways, and all three exist to make one rule structural rather than a matter of care:

There is no field anywhere in the designer for typing a station password, and no reveal control on the device - LVGL normally shows each character for a second and a half as it is typed, and the generated lv_conf.h turns that off.

Access point mode

The board can be its own network, either as a fallback when it cannot join anything or all the time. Unlike a station password, the access point's is configured in the design - it has to be, because an access point publishes the password people need in order to reach it. There is no earlier moment at which somebody could have entered one.

SettingWhat it does
AP nameWhat the network is called.
AP passwordEmpty leaves it open. Otherwise eight characters minimum: softAP() given a shorter one returns success and brings the network up open without saying so, which is why the designer refuses that range rather than warning about it.
Do not broadcastThe network is there but does not appear in a scan. You join it by typing the name.

Set up from a phone

A password cannot be typed on a screen an inch across. WiFi by phone is the other way in: the board starts a network of its own, a phone joins it, and the phone is shown a page - the networks the board can hear, and a box for the password. The board keeps what is chosen and joins. Nothing is typed on the panel at all.

It is in the palette under Ready-made, for the Arduino export on the Espressif chips with Wi-Fi, and is free on every plan - the widget, its action, and the QR code that shows its join code. A design may have it instead of WiFi Setup, or beside it - the two keep the network in the same two settings.

The setup page on a phone: a list of the networks the board can hear, each with its strength and whether it needs a password, and a Search again button.
The page a phone is shown. Its heading is yours to set.

What somebody does

  1. Points a phone’s camera at the code on the panel - or joins the board’s network by its name. The code carries the network’s password, when it has one.
  2. The phone opens the page by itself, as it does for a hotel’s network. Where a phone does not, the line on the panel gives the address to open.
  3. Picks a network from the list, or types its name; gives its password; presses Join.
  4. The page says what became of it - joined, and the address the board was given, or why not - and the board’s own network then closes.

Putting it in a design

  1. Drag WiFi by phone onto a screen. It is an icon: the Wi-Fi mark, in the colour of what setting up is doing.
  2. In its Inspector, press Add the QR code and Add the line that says. The first puts the code a phone scans on the screen; the second a label that says what to do next. Both are ordinary widgets, bound to two of the values below, and yours to move and restyle.
  3. Give the board’s network a name and - better - a password of eight characters or more.

That is all a first set-up needs: with no network to join, the board offers the page by itself.

A 320 x 240 screen with the WiFi by phone icon, a QR code and a line that reads: Join LCD-Setup on a phone to set up Wi-Fi.
The icon, with the QR code and the line its Inspector adds.
SettingDefaultWhat it does
Network nameLCD-SetupThe name of the board’s own network. 32 bytes at most, which is Wi-Fi’s limit.
Its passwordnoneEmpty leaves the board’s network open, so anybody near can join it and choose the network the board joins. Eight characters or more otherwise.
Offers the pageWhile it has no networkWhile it has no network: when there is nothing to join, or the network it knows cannot be joined; gone about twenty seconds after it is on one. All the time: always there, beside the network it has joined. Only when an action opens it.
Page headingWi-Fi setupWhat the page says at its top. The name of the thing being set up reads best.
Reconnect on bootOnJoins the network it was given at start-up.
Join timeout20 sHow long a try is given.
Size, and a colour for each state32 pxNot connected, waiting for a phone (it flashes), a phone is connected, joining, on a network, could not join.

What it has to show

The widget draws a mark and nothing else. What there is to read is values, on the Data tab under Network:

ValueTypeNotes
The code a phone scansTextFor a QR code: a phone’s camera reads it and joins the board’s network, password and all.
What to do nextTextA sentence for a label: which network to join on a phone, that it is joining, the network it is on, or why it could not join.
What it is doing, as a numberInteger0 not connected, 1 waiting for a phone, 2 a phone is connected, 3 joining, 4 on a network, 5 could not join.
Phones on its networkIntegerHow many are joined to the board’s own network at the moment.

The access point’s name and address, and every value in the table further down, are there as well.

Opening it again

The action WiFi by phone does one of three things, from a button, a long press or anything else that fires an event: Open the page brings the board’s network and the page up now, whether or not it is on a network, until a network has been chosen; Close the page stops it; Forget the network it joined drops the network from the board’s settings, and the page then comes up for another.

Worth knowing

The page’s own look (Pro)

WiFi by phone is free, and the page it shows is the one it always was. Part of Pro is making that page yours: switch Own look (Pro) on in the widget’s settings. It is the one setting for the page every phone sees on the board’s network - the WiFi by phone page is the only sign-in page the Arduino export serves, and the phone’s own “sign in to this network” sheet opens it. Arduino export.

SettingDefaultWhat it does
Page headingWi-Fi setupThe page’s heading and title.
Logo, Logo heightnone, 64 pxA picture from the design, sent to the phone as the file it was added as (PNG, JPEG, GIF, WebP or SVG). Keep it under 24 KB: it is compiled into the firmware.
Background, Text, Buttons and accent#F6F8F7, #0D1513, #0A7D4FThe three colours of the page.
Stylesheetportal.cssA file in the export’s data/ folder (the flash filesystem), linked after the page’s own styles so its rules win. Empty for none. A starter is in the export; upload the data/ folder for it.

Everything comes from the board: a phone on its network has no internet, so no fonts or pictures from elsewhere. From code: lw_portalbrand.cpp has portal_brand_configure(portal_brand_t *b), run the first time a phone asks for the page, with b->title, b->bg, b->ink, b->accent (as #rrggbb), b->css_file, b->logo, b->logo_len, b->logo_type and b->logo_height. What it sets wins over the designer. The export writes the file afresh: keep your copy. The board’s name service and the 80 / 8080 arrangement beside a Web server are untouched. Compiled; not yet run on a board.

Wi-Fi switched by the design

Two actions, free as Wi-Fi is, for a design with a WiFi Setup or WiFi by phone (Events). Wi-Fi on or off takes the radio off the air - no network, no access point - and brings it back, rejoining the stored network; it is on at every power-up. Set Wi-Fi network takes a name and a password from a text area, a variable or a setting, stores them where the panel and the phone page store theirs (so a restart joins them) and joins now, switching Wi-Fi on if it was off. The password is never printed, never in the README and never in the design: a variable it is read from must start empty. A Web server in the design starts and stops with Wi-Fi. Arduino export; the MicroPython, ESPHome and ESP-IDF exports say so and do not write them. On an ESP32-P4 whose Wi-Fi is its co-processor’s, switching off is not written yet.

Joining by WPS: the router’s button

One more way in, with nothing typed, for a design with a WiFi Setup or WiFi by phone (Events). Join Wi-Fi by WPS on a button starts it; then press the router’s WPS button within two minutes. The network the router hands over is stored where the panel and the phone page store theirs, so a restart joins it again and Forget forgets it. If no router answers, or WPS fails, the board says so and joins the network it had stored before. Add a WPS button in a WiFi widget’s Inspector adds the button and a label that says what WPS is doing. Push-button mode only. Arduino and ESP-IDF exports; the MicroPython and ESPHome exports say they have no WPS and do not write it. Not on an ESP32-P4 whose Wi-Fi is an ESP32-C6 beside it: ESP-Hosted has no way to start WPS there, and the export refuses. Compiled; not yet run on a board.

What a design can read

The network is a set of variable sources, so an IP address goes on a label through an ordinary binding.

ValueTypeNotes
IP addressTextEmpty until it has joined.
Network nameTextWhat it is joined to.
Signal strengthInteger, dBmAbout -50 is excellent, -85 barely usable. -100 means not joined.
Signal barsInteger0 to 4, for an indicator of strength.
Signal strength, 0 to 100IntegerThe same strength as a share, for a bar: -90 dBm and below is 0, -40 and above is 100.
Link quality, 0 to 100IntegerWhether anything is getting through, not how loud the router is. 0 until it has joined.
Link quality barsIntegerThe same as 0 to 4. This is the one for a Wi-Fi indicator: it falls when packets are being lost, where Signal bars would not.
ConnectedBoolean
Last problemTextWhy the last attempt failed. Worth putting on screen.
Access point running / name / addressBoolean, Text, TextOffered only when the widget runs an access point.
WPS: what it is doing, and as a numberText, IntegerOffered only with Join Wi-Fi by WPS in the design. 0 not started, 1 waiting for the router’s button, 2 joining the network it gave, 3 joined, 4 failed, 5 timed out.

The text ones need a Text variable.

Quality is not strength

A strong signal says the router is loud. It does not say that anything is getting through: a busy channel, a router that has stopped passing traffic or a neighbour's network on top of yours all leave the bars full and the connection useless. So Link quality is measured. In a design that reads it, the board asks its router once a second - a ping, sixteen bytes - and the figure is the share of the last eight seconds' checks that were answered, marked down as the signal weakens: by nothing at -50 dBm, by three quarters at -90. Four bars is 75 and above, three is 50, two is 25, one is anything above nought.

Two things to know. A router can be set to answer no ping at all; until a router has answered one, the figure goes by the signal alone, so such a network reads as its strength and no worse. And the check is to the router, not to the internet: a router that has lost its own line still answers. A design that never reads either value does not ask, and its firmware is what it was.

Wi-Fi on an ESP32-P4

The ESP32-P4 has no radio. The boards that give it Wi-Fi carry a second chip beside it - an ESP32-C6 - wired to the P4's SDIO lines and running Espressif's ESP-Hosted firmware, which makes the C6's radio the P4's. In the designer that chip is a device: Hardware > Devices, under Network, Wi-Fi co-processor. With it in the design every Wi-Fi feature works on the P4 as on any ESP32 - the WiFi Setup and WiFi by phone widgets, web data, MQTT, network data, the Web server and Firmware update, a Clock's time server, the Internet Radio, the AI Assistant and the link-quality values. Without it they are greyed, and say how to add it. For the Arduino export, with nothing to install, because ESP-Hosted is part of the ESP32 core; and for the ESP-IDF export, which takes ESP-Hosted and esp_wifi_remote from Espressif's component registry at the releases that core carries (2.12.11 and 1.6.3), so the C6 runs the same firmware for either.

The P4 board presets that have a C6 bring the device with them, on the board's own pins - every P4 preset here has one: Waveshare's ESP32-P4-WIFI6-Touch-LCD 10.1, 7B and 3.5, their ESP32-P4-NANO with each of its three DSI-TOUCH-A screens, VIEWE's 7" SmartDisplay, Elecrow's CrowPanel Advanced and Guition's JC1060P470C, which has the cable as well. For a board of your own, set its six SDIO lines (CLK, CMD, D0-D3) and the P4 pin that resets the C6 (its EN); they start where Espressif's own P4 board has them: CLK 18, CMD 19, D0-D3 14-17, reset 54. The link to the C6 is brought up in a task of its own on core 0 when the board starts, so the screens never wait for it; Wi-Fi starts once it is up. It runs at the ESP32 core's 40 MHz, which the export cannot lower: the core sets the link up itself and takes only its pins from a sketch.

The C6 has to run ESP-Hosted of the release the ESP32 core expects - the same first two figures: 2.12 for core 3.3.11, which the export's PlatformIO build uses (2.12.11), and for 3.3.12 (2.12.13). A board leaves the factory with whatever its maker put on the C6. The board says both versions on the serial port at start, and a variable can read whether they match (the device's Its firmware matches this build). If they do not, Update my C6 on the board's page writes the core's release to the C6 from the browser, with no Wi-Fi and no password (how, and why). Or the core's own example updates the C6 over the same link: File > Examples > ESP_HostedOTA in the Arduino IDE, with your network's name and password. The export's README has the steps, with this board's pins filled in. A C6 too old or too different for that is flashed directly, through the pads its board brings out for it, as the board's maker says. A C6 that does not answer says so on the screen of a WiFi Setup: The Wi-Fi co-processor is not answering. The link is tried once, at start.

In the ESP-IDF export the C6's seven lines are written into sdkconfig.defaults (CONFIG_ESP_HOSTED_*), which ESP-Hosted reads before the program starts, and the link's 40 MHz is a setting there that can be lowered if the link drops or a panel shows streaks while Wi-Fi is busy. ESP-Hosted has the P4's SD interface slot 1, so an SD card on that interface is on slot 0's own pins - CLK 43, CMD 44, D0-D3 39-42, where Waveshare's boards have it - and the designer says so of a card anywhere else. The serial port says what the C6 answered, or that it did not, as on Arduino; its README says how to update the C6 with ESP-Hosted's own example.

Not through the co-processor here: ESP-NOW, so the Two-way radio is not on a P4, and Bluetooth, which the core can reach through the same chip and this export does not drive there yet. MicroPython and ESPHome do not build for the P4 yet. Nothing here has run on a board.

Wired Ethernet

A board can join a network over a cable instead, or as well. It is a device, not a widget: Hardware > Devices, under Network. For the Arduino export; there is nothing to install, because ESP-IDF's Ethernet driver is part of the ESP32 core. The address comes from the network (DHCP). The driver's own task runs on core 0, beside the network's tasks, so the screens keep the other core to themselves.

PartChipsWiring
Ethernet over SPI - a W5500 module, a DM9051 or a KSZ8851SNLEvery ESP32: the original, S2, S3, C3, C5, C6 and P4SCK, MOSI and MISO on an SPI bus of the design, CS on a pin of its own, and INT and RST. Each works without INT, and is then asked for news every 10 ms. Not on the panel's SPI pins: the panel's library does not share them. An SD card can share its bus.
Ethernet PHY on RMII - a LAN8720, IP101, RTL8201, DP83848, KSZ8041 or KSZ8081The original ESP32 and the ESP32-P4 only: they have the Ethernet controllerMDC, MDIO and the PHY's reset are yours to set. The data lines are fixed: GPIO 19, 21, 22, 25, 26 and 27 on an ESP32, with the 50 MHz clock on GPIO 0 (in, or out) or 16 or 17 (out); GPIO 28, 29, 30, 34, 35 and 49 on a P4, with the clock in on GPIO 50. The device card lists them, and the designer refuses anything else on them - the ESP32's DAC included.

A board preset whose board has an Ethernet socket brings the port with it, already on its pins. Guition's JC1060P470C is the first: an IP101 on the ESP32-P4's own Ethernet pins.

Everything that uses the network works over the cable as it does over Wi-Fi: web data, MQTT, the Web server and Firmware update, a Clock's time server, network data, pictures from a web address, a camera's stream, a radio's playlist and a microphone's send. An ESP32-P4 has no Wi-Fi of its own, so with a cable it gains the Clock, the Weather card, the Web server and the Firmware update. What it says of itself is a set of variable sources, under Ethernet: connected, the IP address, cable connected, the link speed, full duplex, the MAC address and a sentence saying what it is doing. The device card makes a variable for any of them in one press.

Wi-Fi and Ethernet can both be in a design. With both connected the board sends over Wi-Fi: that is ESP-IDF's own order. Two things choose a network of their own, and the setting appears only in a design with both:

One Ethernet port at most. Not yet: a fixed address, MicroPython, ESPHome (which has an Ethernet component of its own, in place of its Wi-Fi block). Nothing here has run on a board yet.

Two things the hardware does

Scanning drops an existing connection. On the ESP32 the radio cannot do both, so the widget only ever scans from the picker, never behind a working link - and when you open the picker while already joined, it remembers what you were on and rejoins it if you leave without picking anything. Search again from a working link therefore costs you a few seconds offline, not the network. Forget is the one thing that clears that memory, which is what makes it different from Back.

ADC2 does not work while WiFi is on. On the classic ESP32 that is GPIO 0, 2, 4, 12-15 and 25-27. An analog input on one of those reads garbage once the radio comes up, so the designer refuses the combination and points you at ADC1 - GPIO 32 to 39.

When it fails

Three different things go wrong and each says so, because "failed" on its own sends people to reset a router when they mistyped a key:

In the preview

A browser cannot scan, so preview shows a plausible list and walks the real flow - pick, type, join, succeed, fail - with the same masking and the same failure text. It is the one part of the designer that is a simulation rather than the thing itself, and it is there so the layout and the failure screen get looked at before anything is flashed.