Partilhar: WhatsApp
aulify
UC UC00643 · T. Desenv. Software, T. Sist. Comp. Redes

Ficha 01 · ESP32 + WiFi + HTTP

Setup, conectividade, APIs REST
Versão · Aluno
Tempo · 45 minutos
Aluno(a)
Turma
Data

Exercício 1 · Setup ESP32

Configura Arduino IDE para suportar ESP32 (adiciona URL nas preferences, instala board package). Liga ESP32 DevKit e faz upload do exemplo Blink usando LED_BUILTIN. Confirma que pisca.

Resposta:
  1. File → Preferences → Additional Boards URLs: https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json

  2. Tools → Board → Boards Manager → procurar "esp32" by Espressif → install.

  3. Liga ESP32 USB. Tools → Board → ESP32 → "ESP32 Dev Module". Tools → Port → seleccionar.

void setup() {
  pinMode(LED_BUILTIN, OUTPUT);   // GPIO 2 em DevKit V1
}

void loop() {
  digitalWrite(LED_BUILTIN, HIGH);
  delay(500);
  digitalWrite(LED_BUILTIN, LOW);
  delay(500);
}

Upload (seta). Mantém botão BOOT premido até começar upload se necessário.

Exercício 2 · Conectar a WiFi

Cria sketch que conecta o ESP32 à tua rede WiFi e imprime no Serial Monitor o IP e RSSI.

Resposta:
#include <WiFi.h>

const char* SSID = "TUA-REDE";
const char* PASS = "TUA-PASSWORD";

void setup() {
  Serial.begin(115200);
  delay(100);

  Serial.print("A conectar a ");
  Serial.println(SSID);

  WiFi.begin(SSID, PASS);

  int tries = 0;
  while (WiFi.status() != WL_CONNECTED && tries < 30) {
    delay(500);
    Serial.print(".");
    tries++;
  }

  if (WiFi.status() == WL_CONNECTED) {
    Serial.println("\nConectado!");
    Serial.print("IP: ");
    Serial.println(WiFi.localIP());
    Serial.print("RSSI: ");
    Serial.print(WiFi.RSSI());
    Serial.println(" dBm");
    Serial.print("MAC: ");
    Serial.println(WiFi.macAddress());
  } else {
    Serial.println("\nFalhou.");
  }
}

void loop() {}

Tools → Serial Monitor → 115200 baud. Output esperado:

A conectar a TUA-REDE
....
Conectado!
IP: 192.168.1.150
RSSI: -55 dBm
MAC: 24:6F:28:AB:CD:EF

Exercício 3 · HTTP GET — clima

Faz pedido HTTP GET a http://wttr.in/Lisbon?format=%t+%C e imprime o resultado. Cada 60 segundos.

Resposta:
#include <WiFi.h>
#include <HTTPClient.h>

const char* SSID = "...";
const char* PASS = "...";

void connectWiFi() {
  WiFi.begin(SSID, PASS);
  while (WiFi.status() != WL_CONNECTED) delay(500);
}

void setup() {
  Serial.begin(115200);
  connectWiFi();
}

void fetchWeather() {
  HTTPClient http;
  http.begin("http://wttr.in/Lisbon?format=%t+%C");
  http.setUserAgent("curl/8.0");   // wttr.in rejeita user-agents desconhecidos

  int code = http.GET();
  if (code == 200) {
    String body = http.getString();
    body.trim();
    Serial.println(body);
  } else {
    Serial.print("Erro ");
    Serial.println(code);
  }
  http.end();
}

void loop() {
  if (WiFi.status() == WL_CONNECTED) {
    fetchWeather();
  }
  delay(60000);
}

Output: +18°C Partly cloudy (varia).

Exercício 4 · API JSON com ArduinoJson

Faz GET a https://api.coingecko.com/api/v3/simple/price?ids=bitcoin&vs_currencies=eur e extrai o preço. Usa library ArduinoJson.

Resposta:

Library Manager → "ArduinoJson" by Benoit Blanchon.

#include <WiFi.h>
#include <HTTPClient.h>
#include <WiFiClientSecure.h>
#include <ArduinoJson.h>

void setup() {
  Serial.begin(115200);
  WiFi.begin("ssid", "pass");
  while (WiFi.status() != WL_CONNECTED) delay(500);
}

void fetchBTC() {
  WiFiClientSecure client;
  client.setInsecure();   // skip TLS validation (dev)

  HTTPClient http;
  http.begin(client, "https://api.coingecko.com/api/v3/simple/price?ids=bitcoin&vs_currencies=eur");

  int code = http.GET();
  if (code != 200) {
    Serial.print("Erro: "); Serial.println(code);
    http.end();
    return;
  }

  String body = http.getString();
  http.end();

  // Parse JSON
  StaticJsonDocument<256> doc;
  DeserializationError err = deserializeJson(doc, body);
  if (err) {
    Serial.println("Parse error");
    return;
  }

  float preco = doc["bitcoin"]["eur"];
  Serial.print("BTC = ");
  Serial.print(preco, 2);
  Serial.println(" €");
}

void loop() {
  fetchBTC();
  delay(300000);   // cada 5 min (rate limits!)
}

Exercício 5 · POST a ThingSpeak

Cria conta thingspeak.com, cria canal com 2 fields. ESP32 lê temperatura simulada (random(20, 30)) e humidade (random(40, 70)) e envia via HTTP GET a cada 30s.

Resposta:
  1. thingspeak.com → sign up.
  2. Channels → New Channel → "Sala" → Field 1 = temp, Field 2 = humid → Save.
  3. API Keys tab → copia Write API Key.
#include <WiFi.h>
#include <HTTPClient.h>

const char* SSID = "...";
const char* PASS = "...";
const char* TS_KEY = "ABCDEFGH12345678";

void setup() {
  Serial.begin(115200);
  WiFi.begin(SSID, PASS);
  while (WiFi.status() != WL_CONNECTED) delay(500);
  randomSeed(analogRead(34));
}

void enviar(float t, float h) {
  HTTPClient http;

  String url = "http://api.thingspeak.com/update?api_key=";
  url += TS_KEY;
  url += "&field1=" + String(t, 2);
  url += "&field2=" + String(h, 2);

  http.begin(url);
  int code = http.GET();
  http.end();

  Serial.print("Enviado: t=");
  Serial.print(t); Serial.print(" h=");
  Serial.print(h); Serial.print(" → ");
  Serial.println(code);
}

void loop() {
  float t = random(200, 300) / 10.0;
  float h = random(400, 700) / 10.0;
  enviar(t, h);
  delay(30000);   // ThingSpeak free: 15s mínimo
}

Visita o teu canal em thingspeak.com → vês gráficos auto-actualizar.

Exercício 6 · DHT22 → ThingSpeak

Liga sensor DHT22 ao pino GPIO 4. Em vez de valores random, envia leituras reais ao ThingSpeak.

Resposta:

Library: "DHT sensor library" by Adafruit + "Adafruit Unified Sensor".

#include <WiFi.h>
#include <HTTPClient.h>
#include <DHT.h>

#define DHT_PIN 4
DHT dht(DHT_PIN, DHT22);

const char* SSID = "...";
const char* PASS = "...";
const char* TS_KEY = "...";

void setup() {
  Serial.begin(115200);
  dht.begin();
  WiFi.begin(SSID, PASS);
  while (WiFi.status() != WL_CONNECTED) delay(500);
}

void loop() {
  float t = dht.readTemperature();
  float h = dht.readHumidity();

  if (isnan(t) || isnan(h)) {
    Serial.println("Erro DHT");
    delay(2000);
    return;
  }

  HTTPClient http;
  String url = "http://api.thingspeak.com/update?api_key=";
  url += TS_KEY;
  url += "&field1=" + String(t, 2);
  url += "&field2=" + String(h, 2);

  http.begin(url);
  http.GET();
  http.end();

  Serial.printf("T=%.1f H=%.1f\n", t, h);
  delay(30000);
}

Hardware DHT22: - VCC → 3.3V (ou 5V). - DATA → GPIO 4 (com pull-up 10kΩ para VCC). - GND → GND.

Exercício 7 · OTA — actualizar via WiFi

Adiciona ao sketch do exercício 6 capacidade de OTA. Faz primeiro upload via USB, depois reinicia e faz segundo upload via Network (sem cabo).

Resposta:
#include <WiFi.h>
#include <HTTPClient.h>
#include <DHT.h>
#include <ArduinoOTA.h>

#define DHT_PIN 4
DHT dht(DHT_PIN, DHT22);

void setupOTA() {
  ArduinoOTA.setHostname("aulify-meteo");
  ArduinoOTA.setPassword("aulify-pass");

  ArduinoOTA.onStart([]() {
    Serial.println("OTA início");
  });
  ArduinoOTA.onEnd([]() {
    Serial.println("OTA fim");
  });
  ArduinoOTA.onError([](ota_error_t error) {
    Serial.printf("OTA erro: %u\n", error);
  });

  ArduinoOTA.begin();
}

void setup() {
  Serial.begin(115200);
  dht.begin();
  WiFi.begin("ssid", "pass");
  while (WiFi.status() != WL_CONNECTED) delay(500);
  setupOTA();
  Serial.println("Pronto. IP=" + WiFi.localIP().toString());
}

unsigned long ultEnv = 0;

void loop() {
  ArduinoOTA.handle();   // chamar sempre

  if (millis() - ultEnv > 30000) {
    ultEnv = millis();
    // ... envio thingspeak
  }
}
  1. Upload USB normal.
  2. Após reset, abre Tools → Port → vai aparecer aulify-meteo at 192.168.1.x (Network).
  3. Selecciona-o.
  4. Próximo upload pede password OTA → put aulify-pass.
  5. Sem fio!

Exercício 8 · Web server simples

Cria web server no ESP32 que serve uma página HTML com leitura actual do DHT22. URL: http://<IP_esp>.

Resposta:
#include <WiFi.h>
#include <WebServer.h>
#include <DHT.h>

#define DHT_PIN 4
DHT dht(DHT_PIN, DHT22);
WebServer server(80);

float lastT = 0, lastH = 0;
unsigned long lastRead = 0;

void readSensor() {
  if (millis() - lastRead > 2000) {
    lastRead = millis();
    float t = dht.readTemperature();
    float h = dht.readHumidity();
    if (!isnan(t)) lastT = t;
    if (!isnan(h)) lastH = h;
  }
}

void handleRoot() {
  readSensor();
  String html = "<!DOCTYPE html><html><head>";
  html += "<meta charset='utf-8'>";
  html += "<meta http-equiv='refresh' content='5'>";
  html += "<title>Aulify Meteo</title>";
  html += "<style>body{font-family:sans-serif;text-align:center;padding:50px;background:#eee}";
  html += "h1{font-size:6em;color:#0070f3}p{font-size:2em}</style>";
  html += "</head><body>";
  html += "<h1>" + String(lastT, 1) + "&deg;C</h1>";
  html += "<p>Humidade: " + String(lastH, 1) + " %</p>";
  html += "<small>Aulify ESP32</small>";
  html += "</body></html>";
  server.send(200, "text/html", html);
}

void setup() {
  Serial.begin(115200);
  dht.begin();
  WiFi.begin("ssid", "pass");
  while (WiFi.status() != WL_CONNECTED) delay(500);
  Serial.println(WiFi.localIP());

  server.on("/", handleRoot);
  server.begin();
}

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

Abre http://<IP_do_esp32>/ no browser → vês temperatura grande. Auto-refresh cada 5s.