WiFi, simulated

The board can join a network, fetch a page and serve one. The radio is simulated: there is no 802.11, no real internet, and the WiFi runtime is ours.

The radio is simulated. There is no 802.11 anywhere in Mokxi and nothing a sketch does can reach the network your browser is on. What is faithful is the Arduino code you write, which is the whole point, because it is the code you would write for a real board.

Five boards have it, and they are the five that have a radio on the real hardware: the ESP32-C3, the ESP32-C6, the classic ESP32 DevKit, the ESP8266 NodeMCU and the Raspberry Pi Pico W. On every other board here, including a plain Raspberry Pi Pico, which has no wireless part on it, #include <WiFi.h> stops with a sentence saying so rather than writing to an address its chip does not have. That is on purpose: a stub that answered "not connected" would be a lie with a plausible shape, and a compile error is not.

What is real and what is not

Real, in the sense that it behaves the way your board will:

  • the calls (WiFi.begin(), WiFi.status(), WiFi.localIP(), HTTPClient, WebServer) with the signatures a tutorial gives you;
  • the status codes, which are Arduino's own enum, value for value;
  • the timing: joining takes between one and three seconds, and a wrong password fails after five, which is where a real board on a quiet network lands;
  • the cost: a fetch really takes 60 ms of the sketch's time, and a sketch that forgets server.handleClient() really never answers.

Not real, and never pretended to be:

  • no radio. No channel, no scan, no scanNetworks(), no beacon, no WPA2, no encryption of any kind. The password is compared as a string.
  • no real internet. No TCP, no DNS, no sockets, nothing that leaves the browser tab. Four made-up names exist and no others.
  • no TLS. WiFiClientSecure compiles and then fails, saying so. An https:// URL fails the same way. A TLS that trusted everything would teach you that https is free.
  • no second machine. One board, one network, one address. Nothing outside this browser tab can reach the server your sketch runs.
  • RSSI() is a setting, not a measurement. Moving the board on the canvas changes nothing.
  • no Bluetooth. The ESP32, the C6 and the Pico W all do Bluetooth on real hardware. None of it is here, and there is no header to fail on.

Setting up the network

Click the board and look at the properties panel: wifiSsid, wifiPassword and wifiRssi. Those three are the one access point this board can see. With no radio there is nothing to scan, so the network is a property of the board rather than a part you place beside it.

Match them in your sketch and it joins. Get either one wrong on purpose and watch what happens. That is the more useful lesson of the two.

The Cloud panel edits the same three while the sketch is running, so you can pull the network out from under a running board and see the connect loop start again.

Joining

#include <WiFi.h>

void setup() {
  Serial.begin(115200);
  WiFi.begin("Mokxi-Lab", "breadboard");
  while (WiFi.status() != WL_CONNECTED) {
    Serial.print(".");
    delay(250);
  }
  Serial.println(WiFi.localIP());   // 192.168.4.2
}

WiFi.status() walks WL_IDLE_STATUS, then WL_DISCONNECTED while it associates, then WL_CONNECTED. There is no WL_CONNECTING in Arduino, which is why the loop above is written the way every tutorial writes it.

A wrong password becomes WL_CONNECT_FAILED after five seconds. A name that is not the one on the board becomes WL_NO_SSID_AVAIL. The address is always 192.168.4.2, and it is the same address after a disconnect() and a second begin().

Fetching

#include <HTTPClient.h>
WiFiClient client;
HTTPClient http;
http.begin(client, "http://weather.mokxi/");
int code = http.GET();
if (code > 0) Serial.println(http.getString());
else Serial.println(HTTPClient::errorToString(code));
http.end();

Three addresses exist on this simulated internet:

  • http://time.mokxi/: the simulation's clock, as an ISO string. It is the kernel's clock counted from a fixed midnight, not the time of day, because the simulation does not know what day it is.
  • http://weather.mokxi/: JSON with a temperature and a humidity you set in the Cloud panel. Change one and the next fetch brings the new number back.
  • http://echo.mokxi/: whatever you POST, straight back.

Anything else does not resolve. http://example.com/ comes back as HTTPC_ERROR_CONNECTION_REFUSED, and HTTPClient::errorToString() tells you why in one line: no real internet: names under .mokxi only. That refusal is readable from the sketch on purpose. It is a thing worth teaching, not a thing to hide.

Serving

#include <WebServer.h>
WebServer server(80);

void setup() {
  // ... join the network first ...
  server.on("/", [](){ server.send(200, "text/html", "<h1>hello</h1>"); });
  server.begin();
}

void loop() { server.handleClient(); }

on(path, handler), onNotFound(), send(code, type, body), arg(name), hasArg(), uri() and method(). Your handlers are your code, running on the board's core at the board's clock.

The Web panel (a tab beside Serial along the bottom) is the browser for them. It has an address bar starting at http://192.168.4.2/, a Refresh, and the page itself in a frame with scripts switched off. Links and buttons in that page come back round into your sketch, which is what makes "switch the LED from a web page" work end to end.

If the page never arrives, the panel says so, and after ten seconds the network answers 504 itself: the usual reason is a loop() that has stopped calling handleClient().

The Cloud panel

Every request, both ways: what the board asked the simulated internet for, and what the Web panel asked the board for, with the method, the address, the status, the bodies and, when something failed, a line saying why. It is the network tab for a board.

It also holds the two weather.mokxi dials and the three access-point settings, so a lesson can turn one and watch the sketch notice.

Try these

  • WiFi: join the network: the connect loop, the address and the signal.
  • WiFi: fetch the weather: HTTPClient against weather.mokxi, and a deliberate request to example.com so you read the refusal yourself.
  • WiFi: a lamp on a web page: two buttons and a form that switch the LED on GPIO 8.

On every WiFi board (the ESP32-C3, ESP32-C6, Pico W, ESP32 DevKit, ESP32-S3 and ESP8266) all three compile in the browser, exactly like every other example.

The whole contract, register by register and limit by limit, is in Simulated WiFi.