/* * ============================================================================= * Fab Academy 2026 — Week 15 — Yaroslav Artsishevskiy * Web buttons → LED modes (off / blink / fade) * ----------------------------------------------------------------------------- * Three buttons in the browser: * [Toggle] — turn the LED on or off (same as before) * [Blink] — LED blinks once per second * [Fade] — LED fades smoothly up and down * * How it works: * Each button calls a different URL on the ESP32: * /toggle → flip ON ↔ OFF (and stop any animation) * /blink → enter blink mode * /fade → enter fade mode * The board remembers the current mode in a variable. * The main loop() runs the animation for whichever mode is active. * ============================================================================= */ #include #include "Network.h" #include "WiFi.h" #include NetworkUDP udp; WebServer server(80); const char* ssid = "YaroUDP"; const char* password = "12345678"; IPAddress local_IP(192, 168, 4, 1); IPAddress gateway(192, 168, 4, 1); IPAddress subnet(255, 255, 255, 0); const uint16_t udpPort = 1234; // On-board user LED on the XIAO ESP32-C3 is GPIO 21, active LOW const int LED_PIN = 21; // ---- Modes ---------------------------------------------------------------- // The LED can be in one of three modes. The current mode tells loop() // what to do on every iteration. enum Mode { MODE_OFF, MODE_ON, MODE_BLINK, MODE_FADE }; Mode currentMode = MODE_OFF; // ---- The webpage ---------------------------------------------------------- // Three buttons. Each one calls a different URL with fetch(). const char HTML_PAGE[] PROGMEM = R"HTML( YaroLED

YaroLED

)HTML"; // ---- HTTP handlers -------------------------------------------------------- void handleRoot() { server.send_P(200, "text/html", HTML_PAGE); } // /toggle: flip between ON and OFF, and leave any animation mode. void handleToggle() { if (currentMode == MODE_ON) currentMode = MODE_OFF; else currentMode = MODE_ON; Serial.println(currentMode == MODE_ON ? "ON" : "OFF"); server.send(200, "text/plain", "OK"); } // /blink: enter blinking mode. void handleBlink() { currentMode = MODE_BLINK; Serial.println("BLINK"); server.send(200, "text/plain", "OK"); } // /fade: enter fading mode. void handleFade() { currentMode = MODE_FADE; Serial.println("FADE"); server.send(200, "text/plain", "OK"); } // ---- Setup ---------------------------------------------------------------- void setup() { Serial.begin(115200); delay(1000); pinMode(LED_PIN, OUTPUT); digitalWrite(LED_PIN, HIGH); // start OFF (active LOW) Network.begin(); WiFi.mode(WIFI_AP); WiFi.softAPConfig(local_IP, gateway, subnet); WiFi.softAP(ssid, password); udp.begin(udpPort); server.on("/", handleRoot); server.on("/toggle", handleToggle); server.on("/blink", handleBlink); server.on("/fade", handleFade); server.begin(); Serial.println("Ready"); Serial.print("AP IP: "); Serial.println(WiFi.softAPIP()); } // ---- Loop ----------------------------------------------------------------- // Two jobs every loop: // 1. Let the web server handle any new HTTP requests. // 2. Update the LED according to the current mode. // // We use millis() (not delay()) so the web server keeps responding while // the LED animates. delay() would freeze the whole board. void loop() { server.handleClient(); switch (currentMode) { case MODE_OFF: digitalWrite(LED_PIN, HIGH); // OFF (active LOW) break; case MODE_ON: digitalWrite(LED_PIN, LOW); // ON break; case MODE_BLINK: { // Blink once per second: ON for 500 ms, OFF for 500 ms. // (millis() / 500) % 2 gives 0,1,0,1,0,1... once every 500 ms. bool on = (millis() / 500) % 2 == 0; digitalWrite(LED_PIN, on ? LOW : HIGH); break; } case MODE_FADE: { // Smooth fade up and down using PWM (analogWrite). // A sine wave gives a nice breathing curve. // millis() * 0.002 means a full cycle takes ~3 seconds. float wave = (sin(millis() * 0.002) + 1.0) / 2.0; // 0.0 to 1.0 int brightness = wave * 255; // 0 to 255 // Active LOW means we have to invert: 255 = full ON for analogWrite analogWrite(LED_PIN, 255 - brightness); break; } } // Week 11 UDP listener — kept as it was int packetSize = udp.parsePacket(); if (packetSize) { char incoming[255]; int len = udp.read(incoming, sizeof(incoming) - 1); if (len > 0) incoming[len] = '\0'; Serial.print("Received UDP: "); Serial.println(incoming); } }