whiplk

Untitled

Aug 17th, 2026
39
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Arduino 8.83 KB | Gaming | 0 0
  1.  
  2. // BSides Fortaleza 2026 — Portal do Crachá
  3. // Sobe uma rede WiFi própria (AP) com portal cativo e serve, via HTTP,
  4. // um site estático com a programação do evento, mais uma página de
  5. // configuração do Wi-Fi / funções dos botões / leitura do sensor SHTC3.
  6. // WiFi, WebServer, DNSServer e Preferences já vêm no core esp32 (sem
  7. // libs extras); só o sensor usa uma lib externa (Adafruit SHTC3).
  8.  
  9. #include <WiFi.h>
  10. #include <WebServer.h>
  11. #include <DNSServer.h>
  12. #include <Preferences.h>
  13. #include <Wire.h>
  14. #include "Adafruit_SHTC3.h"
  15.  
  16. #include "webpage.h"
  17. #include "config_page.h"
  18. #include "cronograma_img.h"
  19. #include "source_files.h"  // gerado por gen_sources.py a cada build
  20.  
  21. // ---- Hardware do crachá (pinos do sketch original example.ino) ----
  22. #define LED_RED     1
  23. #define LED_YELLOW  3
  24. #define LED_GREEN   5
  25. #define BTN_RED     4
  26. #define BTN_YELLOW  6
  27. #define BTN_GREEN   7
  28. #define BUZZER      11
  29.  
  30. Adafruit_SHTC3 shtc3 = Adafruit_SHTC3();
  31. bool sensorOk = false;
  32.  
  33. bool lastRed = HIGH, lastYellow = HIGH, lastGreen = HIGH;
  34.  
  35. // ---- Config persistida em NVS (Preferences) ----
  36. // PLACA_NUM é injetado no build por `make upload PLACA=N` (ver Makefile).
  37. // Sem PLACA, o SSID padrão fica sem sufixo, igual antes.
  38. #ifndef PLACA_NUM
  39. #define PLACA_NUM 0
  40. #endif
  41. #define _STR(x) #x
  42. #define _XSTR(x) _STR(x)
  43.  
  44. #if PLACA_NUM > 0
  45. const char* DEFAULT_SSID = "BSides Fortaleza 2026_" _XSTR(PLACA_NUM);
  46. #else
  47. const char* DEFAULT_SSID = "BSides Fortaleza 2026";
  48. #endif
  49. const char* DEFAULT_PASSWORD = "";  // "" = rede aberta
  50.  
  51. Preferences prefs;
  52. String cfgSsid, cfgPass, cfgLblRed, cfgLblYellow, cfgLblGreen;
  53.  
  54. const IPAddress AP_IP(192, 168, 4, 1);
  55. const IPAddress AP_GATEWAY(192, 168, 4, 1);
  56. const IPAddress AP_SUBNET(255, 255, 255, 0);
  57. const byte      DNS_PORT = 53;
  58.  
  59. DNSServer dnsServer;
  60. WebServer server(80);
  61.  
  62. // ---------------- config: load / save / apply ----------------
  63.  
  64. void loadConfig() {
  65.   prefs.begin("badge", true);
  66.   cfgSsid      = prefs.getString("ssid", DEFAULT_SSID);
  67.   cfgPass      = prefs.getString("pass", DEFAULT_PASSWORD);
  68.   cfgLblRed    = prefs.getString("lblRed", "Vermelho");
  69.   cfgLblYellow = prefs.getString("lblYellow", "Amarelo");
  70.   cfgLblGreen  = prefs.getString("lblGreen", "Verde");
  71.   prefs.end();
  72. }
  73.  
  74. void saveConfig() {
  75.   prefs.begin("badge", false);
  76.   prefs.putString("ssid", cfgSsid);
  77.   prefs.putString("pass", cfgPass);
  78.   prefs.putString("lblRed", cfgLblRed);
  79.   prefs.putString("lblYellow", cfgLblYellow);
  80.   prefs.putString("lblGreen", cfgLblGreen);
  81.   prefs.end();
  82. }
  83.  
  84. void applyAP() {
  85.   WiFi.softAPdisconnect(true);
  86.   delay(100);
  87.   WiFi.softAPConfig(AP_IP, AP_GATEWAY, AP_SUBNET);
  88.   if (cfgPass.length() > 0) {
  89.     WiFi.softAP(cfgSsid.c_str(), cfgPass.c_str(), 1, 0, 8);
  90.   } else {
  91.     WiFi.softAP(cfgSsid.c_str(), nullptr, 1, 0, 8);
  92.   }
  93.   Serial.println("AP -> SSID: " + cfgSsid + (cfgPass.length() ? " (com senha)" : " (aberta)"));
  94.   Serial.println("IP: " + WiFi.softAPIP().toString());
  95. }
  96.  
  97. String jsonEscape(const String &s) {
  98.   String out;
  99.   out.reserve(s.length() + 4);
  100.   for (size_t i = 0; i < s.length(); i++) {
  101.     char c = s[i];
  102.     if (c == '"' || c == '\\') out += '\\';
  103.     out += c;
  104.   }
  105.   return out;
  106. }
  107.  
  108. // ---------------- rotas HTTP ----------------
  109.  
  110. void handleRoot() {
  111.   server.send_P(200, "text/html", INDEX_HTML);
  112. }
  113.  
  114. void handleConfigPage() {
  115.   server.send_P(200, "text/html", CONFIG_HTML);
  116. }
  117.  
  118. void handleDownloadIno() {
  119.   server.sendHeader("Content-Disposition", "attachment; filename=\"code2026.ino\"");
  120.   server.send_P(200, "text/plain", SRC_INO);
  121. }
  122.  
  123. void handleDownloadWebpageH() {
  124.   server.sendHeader("Content-Disposition", "attachment; filename=\"webpage.h\"");
  125.   server.send_P(200, "text/plain", SRC_WEBPAGE_H);
  126. }
  127.  
  128. void handleDownloadConfigH() {
  129.   server.sendHeader("Content-Disposition", "attachment; filename=\"config_page.h\"");
  130.   server.send_P(200, "text/plain", SRC_CONFIG_H);
  131. }
  132.  
  133. void handleImage() {
  134.   server.send_P(200, "image/jpeg", (PGM_P)CRONOGRAMA_JPG, CRONOGRAMA_JPG_LEN);
  135. }
  136.  
  137. void handleApiConfigGet() {
  138.   String json = "{";
  139.   json += "\"ssid\":\""      + jsonEscape(cfgSsid)      + "\",";
  140.   json += "\"pass\":\""      + jsonEscape(cfgPass)      + "\",";
  141.   json += "\"lblRed\":\""    + jsonEscape(cfgLblRed)    + "\",";
  142.   json += "\"lblYellow\":\"" + jsonEscape(cfgLblYellow) + "\",";
  143.   json += "\"lblGreen\":\""  + jsonEscape(cfgLblGreen)  + "\"";
  144.   json += "}";
  145.   server.send(200, "application/json", json);
  146. }
  147.  
  148. void handleApiConfigPost() {
  149.   bool wantsApplyAP = false;
  150.  
  151.   if (server.hasArg("ssid")) {
  152.     String newSsid = server.arg("ssid");
  153.     newSsid.trim();
  154.     if (newSsid.length() == 0) {
  155.       server.send(400, "application/json", "{\"ok\":false,\"error\":\"SSID nao pode ser vazio\"}");
  156.       return;
  157.     }
  158.     String newPass = server.hasArg("pass") ? server.arg("pass") : "";
  159.     if (newPass.length() > 0 && newPass.length() < 8) {
  160.       server.send(400, "application/json", "{\"ok\":false,\"error\":\"Senha precisa ter 8+ caracteres, ou vazia p/ rede aberta\"}");
  161.       return;
  162.     }
  163.     cfgSsid = newSsid;
  164.     cfgPass = newPass;
  165.     wantsApplyAP = true;
  166.   }
  167.  
  168.   if (server.hasArg("lblRed"))    cfgLblRed    = server.arg("lblRed");
  169.   if (server.hasArg("lblYellow")) cfgLblYellow = server.arg("lblYellow");
  170.   if (server.hasArg("lblGreen"))  cfgLblGreen  = server.arg("lblGreen");
  171.  
  172.   saveConfig();
  173.   server.send(200, "application/json", "{\"ok\":true}");
  174.  
  175.   if (wantsApplyAP) {
  176.     delay(300);  // dá tempo da resposta HTTP sair antes de trocar de rede
  177.     applyAP();
  178.   }
  179. }
  180.  
  181. void handleApiSensor() {
  182.   String json;
  183.   if (sensorOk) {
  184.     sensors_event_t humidity, temp;
  185.     if (shtc3.getEvent(&humidity, &temp)) {
  186.       json = "{\"ok\":true,\"temp\":" + String(temp.temperature, 1) +
  187.              ",\"hum\":" + String(humidity.relative_humidity, 1) + "}";
  188.     } else {
  189.       json = "{\"ok\":false}";
  190.     }
  191.   } else {
  192.     json = "{\"ok\":false}";
  193.   }
  194.   server.send(200, "application/json", json);
  195. }
  196.  
  197. // Qualquer host/caminho desconhecido volta pra home — é isso que faz o
  198. // celular detectar portal cativo e abrir a página sozinho.
  199. void handleNotFound() {
  200.   server.sendHeader("Location", String("http://") + AP_IP.toString() + "/", true);
  201.   server.send(302, "text/plain", "");
  202. }
  203.  
  204. // ---------------- botões / LEDs / buzzer ----------------
  205.  
  206. void beep(int ledPin, int vezes) {
  207.   for (int i = 0; i < vezes; i++) {
  208.     digitalWrite(ledPin, HIGH);
  209.     tone(BUZZER, 2000);
  210.     delay(100);
  211.     digitalWrite(ledPin, LOW);
  212.     noTone(BUZZER);
  213.     delay(100);
  214.   }
  215. }
  216.  
  217. void pollButtons() {
  218.   bool red    = digitalRead(BTN_RED);
  219.   bool yellow = digitalRead(BTN_YELLOW);
  220.   bool green  = digitalRead(BTN_GREEN);
  221.  
  222.   if (red == LOW && lastRed == HIGH) {
  223.     delay(30);
  224.     beep(LED_RED, 3);
  225.   }
  226.   if (yellow == LOW && lastYellow == HIGH) {
  227.     delay(30);
  228.     beep(LED_YELLOW, 2);
  229.   }
  230.   if (green == LOW && lastGreen == HIGH) {
  231.     delay(30);
  232.     beep(LED_GREEN, 1);
  233.   }
  234.  
  235.   lastRed    = red;
  236.   lastYellow = yellow;
  237.   lastGreen  = green;
  238. }
  239.  
  240. // ---------------- setup / loop ----------------
  241.  
  242. void setup() {
  243.   Serial.begin(115200);
  244.   delay(200);
  245.  
  246.   pinMode(LED_RED, OUTPUT);
  247.   pinMode(LED_YELLOW, OUTPUT);
  248.   pinMode(LED_GREEN, OUTPUT);
  249.   pinMode(BUZZER, OUTPUT);
  250.   pinMode(BTN_RED, INPUT);
  251.   pinMode(BTN_YELLOW, INPUT);
  252.   pinMode(BTN_GREEN, INPUT);
  253.  
  254.   sensorOk = shtc3.begin();
  255.   Serial.println(sensorOk ? "Sensor SHTC3 encontrado" : "Sensor SHTC3 nao encontrado");
  256.  
  257.   loadConfig();
  258.  
  259.   WiFi.mode(WIFI_AP);
  260.   applyAP();
  261.  
  262.   dnsServer.start(DNS_PORT, "*", AP_IP);
  263.  
  264.   server.on("/", handleRoot);
  265.   server.on("/config", handleConfigPage);
  266.   server.on("/cronograma.jpg", handleImage);
  267.   server.on("/api/config", HTTP_GET, handleApiConfigGet);
  268.   server.on("/api/config", HTTP_POST, handleApiConfigPost);
  269.   server.on("/api/sensor", HTTP_GET, handleApiSensor);
  270.   server.on("/download/code2026.ino", handleDownloadIno);
  271.   server.on("/download/webpage.h", handleDownloadWebpageH);
  272.   server.on("/download/config_page.h", handleDownloadConfigH);
  273.  
  274.   // Endpoints de detecção de portal cativo dos principais sistemas.
  275.   server.on("/generate_204", handleRoot);              // Android
  276.   server.on("/gen_204", handleRoot);
  277.   server.on("/hotspot-detect.html", handleRoot);        // iOS / macOS
  278.   server.on("/library/test/success.html", handleRoot);
  279.   server.on("/ncsi.txt", handleRoot);                   // Windows
  280.   server.on("/connecttest.txt", handleRoot);
  281.  
  282.   server.onNotFound(handleNotFound);
  283.   server.begin();
  284.  
  285.   Serial.println("=================================");
  286.   Serial.print("SSID: "); Serial.println(cfgSsid);
  287.   Serial.print("IP:   "); Serial.println(WiFi.softAPIP());
  288.   Serial.println("=================================");
  289. }
  290.  
  291. void loop() {
  292.   dnsServer.processNextRequest();
  293.   server.handleClient();
  294.   pollButtons();
  295. }
  296.  
Advertisement
Add Comment
Please, Sign In to add comment