Level 3Unit A · Session 4
4

Unit A · On the network

A button that reaches back

What we are making: a control on the page. You tap it on your phone and something physical happens on the board, across the room.

The idea

So far the information goes one way: board to screen. Now it goes both ways. The phone asks for a different address, and the board treats that request as an instruction.

Tank Alarm — Team 4http://192.168.4.1Water level23 cmAlarmARMED SilenceArmSilenced 12 s ago

Two buttons. Each one is just a different address the board recognises.

New words
RouteA named address the server knows about: / or /on or /silence.
RequestThe phone asking for an address.
StateSomething the board remembers between requests — like whether the alarm is silenced.
RedirectTelling the browser 'now go and load this other page instead'.

The code

The new parts only — keep everything else from Session 3
1bool silenced = false; // the board remembers this
2 
3void handleRoot() {
4 int cm = readDistance();
5 String page = "<html><head><meta name='viewport' content='width=device-width'>";
6 page += "<style>body{font-family:sans-serif;padding:20px}";
7 page += "a{display:inline-block;padding:14px 22px;border-radius:8px;";
8 page += "background:#1B4F8A;color:#fff;text-decoration:none;font-size:18px}</style>";
9 page += "</head><body>";
10 page += "<h2>Tank Alarm - Team 4</h2>";
11 page += "<p>Water level: <b>" + String(cm) + " cm</b></p>";
12 page += "<p>Alarm: <b>" + String(silenced ? "SILENCED" : "ARMED") + "</b></p>";
13 page += "<p><a href='/toggle'>Silence / Arm</a></p>";
14 page += "</body></html>";
15 server.send(200, "text/html", page);
16}
17 
18void handleToggle() {
19 silenced = !silenced; // flip it
20 Serial.print("Alarm silenced: ");
21 Serial.println(silenced);
22 server.sendHeader("Location", "/"); // go back to the main page
23 server.send(303);
24}
25 
26void setup() {
27 // ... wifi and pins as before ...
28 server.on("/", handleRoot);
29 server.on("/toggle", handleToggle);
30 server.begin();
31}
  • Line 1 — declared outside both functions, so it survives between requests. Inside a function it would reset every time.
  • Line 12 — silenced ? "SILENCED" : "ARMED" is a compact if. Read it as: if silenced, the first, otherwise the second.
  • Line 19 — ! means not. silenced = !silenced flips true to false and back.
  • Line 22–23 — the redirect. Without it the browser sits on a blank /toggle page, and reloading it would toggle again. That bug is genuinely confusing when you meet it by accident.
  • Line 29 — a second route. You can add as many as you like.

Make it do something physical

A page that changes a variable is not convincing. Wire a buzzer and let the alarm actually sound, so the button has a consequence you can hear from the corridor.

ESP32GPIO 19GNDBuzzeractive type+-ACTIVE buzzer: makes its own tone. digitalWrite HIGH and it sounds.PASSIVE buzzer: needs a tone driven into it, and will click, not beep.A small buzzer draws under 30 mA and is safe straight off a pin.A relay, lamp or siren is not. Those get their own supply and a driver.
The one output you can wire directly. Almost nothing else qualifies.
Now the button matters
1const int BUZZER = 19;
2 
3void loop() {
4 server.handleClient();
5 
6 int cm = readDistance();
7 bool tooHigh = (cm > 0 && cm < 10); // cm > 0 skips the -1 no-reading case
8 
9 if (tooHigh && !silenced) {
10 digitalWrite(BUZZER, HIGH);
11 } else {
12 digitalWrite(BUZZER, LOW);
13 }
14}
⚠ Careful
Line 7 is the habit of the year: cm > 0 && before you trust the reading. A −1 is less than 10, so without that check a disconnected sensor sets off the alarm permanently.
Pins used51819GND

Try it

  1. Upload. Join the network. Open the page.
  2. Block the sensor with your hand. The buzzer sounds.
  3. Tap Silence on your phone. It stops, while your hand is still there.
  4. Move your hand away, put it back. Does it sound again? Should it?
  5. Decide as a team, then change the code so it does what you decided.
💡 Tip
That last step is a real design question with no correct answer. A fire alarm and a fridge-door alarm answer it differently, and both are right.

What you learned

  • A route is just a name the server recognises.
  • State lives outside functions or it does not live at all.
  • Redirect after an action, or the browser gets stuck on it.
  • Check your reading is real before you act on it.
Challenge optional — only if you finish early
  • Add a third route that does something neither of the first two do.
3. The first value on a screen