LED via Mobile 📱💡
Controle o LED do ESP32 usando um botão no seu celular!
🎯 Objetivo desta atividade
Criar um sistema completo onde um app no celular envia comandos para ligar/desligar o LED do ESP32. O ESP32 vai consultar uma API PHP para receber os comandos via WiFi.
🏗️ Como funciona?
App Mobile
Expo Snack
API PHP
Servidor XAMPP
ESP32
Arduino IDE
O app envia comandos para a API. O ESP32 consulta a API e executa os comandos.
📚 Conceitos Novos
WiFi.h
Biblioteca do ESP32 para conectar em redes WiFi.
HTTPClient.h
Biblioteca para fazer requisições HTTP (GET, POST).
useState (React)
Hook que cria uma "variável reativa" no React - quando muda, a tela atualiza!
fetch (JavaScript)
Função para fazer requisições HTTP no JavaScript/React Native.
Backend - API PHP
Editar no VS Code
Primeiro, vamos criar a API que vai intermediar a comunicação entre o app e o ESP32. Esta API salva e retorna o estado atual do LED.
📁 Onde criar: Salve este arquivo em
C:\xampp\htdocs\iot\api\led.php
<?php
/**
* API simples para controle do LED
* Armazena o estado em um arquivo JSON
*/
// Permitir requisições de qualquer origem (CORS)
header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Methods: GET, POST, OPTIONS");
header("Access-Control-Allow-Headers: Content-Type");
header("Content-Type: application/json");
// Responder preflight (OPTIONS)
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
http_response_code(200);
exit();
}
// Arquivo que armazena o estado do LED
$arquivo = __DIR__ . '/led_estado.json';
// Inicializar arquivo se não existir
if (!file_exists($arquivo)) {
file_put_contents($arquivo, json_encode(['ligado' => false]));
}
// GET: Retorna o estado atual do LED
if ($_SERVER['REQUEST_METHOD'] === 'GET') {
$estado = json_decode(file_get_contents($arquivo), true);
echo json_encode([
'success' => true,
'ligado' => $estado['ligado'] ?? false
]);
exit();
}
// POST: Altera o estado do LED
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$dados = json_decode(file_get_contents('php://input'), true);
if (isset($dados['ligado'])) {
$novoEstado = ['ligado' => (bool)$dados['ligado']];
file_put_contents($arquivo, json_encode($novoEstado));
echo json_encode([
'success' => true,
'message' => 'Estado atualizado!',
'ligado' => $novoEstado['ligado']
]);
} else {
http_response_code(400);
echo json_encode(['success' => false, 'error' => 'Campo "ligado" é obrigatório']);
}
exit();
}
// Método não suportado
http_response_code(405);
echo json_encode(['error' => 'Método não permitido']);
?>
CORS Headers
As linhas com Access-Control-Allow-* permitem que
o app mobile (que está em outro domínio) acesse a API. Sem isso, o navegador bloqueia!
Armazenamento em JSON
Usamos um arquivo led_estado.json para simplicidade.
Em produção, você usaria o banco de dados MySQL!
ESP32 - Código WiFi
Upload via Arduino IDE
⚠️ Atenção: Você precisa alterar o SSID
e SENHA para sua rede WiFi, e o
IP do servidor para o IP do seu computador!
/************************************************
* LED CONTROLADO VIA MOBILE - ESP32
* O ESP32 consulta a API a cada segundo
* e liga/desliga o LED conforme o comando
***********************************************/
#include <WiFi.h>
#include <HTTPClient.h>
// ========== CONFIGURAÇÕES ==========
// ALTERE PARA SUA REDE WIFI!
const char* SSID = "NOME_DA_SUA_REDE";
const char* SENHA = "SENHA_DA_SUA_REDE";
// ALTERE PARA O IP DO SEU COMPUTADOR!
// Descubra com: ipconfig (Windows) ou ifconfig (Linux/Mac)
const char* URL_API = "http://192.168.1.100/iot/api/led.php";
// Pino do LED
const int PINO_LED = 13;
void setup() {
Serial.begin(115200);
// Configura o LED como saída
pinMode(PINO_LED, OUTPUT);
digitalWrite(PINO_LED, LOW);
// Conecta ao WiFi
Serial.println("Conectando ao WiFi...");
WiFi.begin(SSID, SENHA);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("✅ WiFi conectado!");
Serial.print("IP: ");
Serial.println(WiFi.localIP());
Serial.println("Aguardando comandos do app...");
}
void loop() {
if (WiFi.status() == WL_CONNECTED) {
HTTPClient http;
// Faz requisição GET para a API
http.begin(URL_API);
int httpCode = http.GET();
if (httpCode == 200) {
String resposta = http.getString();
// Verifica se deve ligar o LED
if (resposta.indexOf("\"ligado\":true") > 0) {
digitalWrite(PINO_LED, HIGH);
Serial.println("💡 LED LIGADO");
} else {
digitalWrite(PINO_LED, LOW);
Serial.println("🔌 LED DESLIGADO");
}
} else {
Serial.print("Erro HTTP: ");
Serial.println(httpCode);
}
http.end();
} else {
Serial.println("⚠️ WiFi desconectado! Reconectando...");
WiFi.begin(SSID, SENHA);
}
// Consulta a cada 1 segundo
delay(1000);
}
🔍 Como descobrir o IP do computador?
Windows
ipconfig
Procure por "IPv4 Address"
Linux/Mac
ifconfig
Procure por "inet"
App Mobile - Expo Snack
Programar em snack.expo.dev
Este código cria um botão grande e bonito que muda de cor quando você toca. Ao tocar, ele envia o comando para a API!
⚠️ Importante: Altere a variável URL_API
para o IP do seu computador (o mesmo que você colocou no ESP32).
/**
* App de Controle do LED - Etapa 2
* Tutorial do Prof. Reginaldo
*/
import React, { useState, useEffect } from 'react';
import {
View,
Text,
TouchableOpacity,
StyleSheet,
ActivityIndicator
} from 'react-native';
// ⚠️ ALTERE PARA O IP DO SEU COMPUTADOR!
const URL_API = 'http://192.168.1.100/iot/api/led.php';
export default function App() {
// Estado do LED (true = ligado, false = desligado)
const [ligado, setLigado] = useState(false);
const [carregando, setCarregando] = useState(false);
const [erro, setErro] = useState(null);
// Carregar estado inicial ao abrir o app
useEffect(() => {
carregarEstado();
}, []);
// Função para carregar o estado atual do LED
const carregarEstado = async () => {
try {
const resposta = await fetch(URL_API);
const dados = await resposta.json();
setLigado(dados.ligado);
setErro(null);
} catch (e) {
setErro('Erro ao conectar com a API');
}
};
// Função para alternar o estado do LED
const alternarLED = async () => {
setCarregando(true);
try {
const novoEstado = !ligado;
const resposta = await fetch(URL_API, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ ligado: novoEstado })
});
const dados = await resposta.json();
if (dados.success) {
setLigado(novoEstado);
setErro(null);
}
} catch (e) {
setErro('Erro ao enviar comando');
}
setCarregando(false);
};
return (
<View style={styles.container}>
<Text style={styles.titulo}>💡 Controle do LED</Text>
<Text style={styles.subtitulo}>Toque para ligar/desligar</Text>
<TouchableOpacity
style={[
styles.botao,
ligado ? styles.botaoLigado : styles.botaoDesligado
]}
onPress={alternarLED}
disabled={carregando}
>
{carregando ? (
<ActivityIndicator size="large" color="#fff" />
) : (
<>
<Text style={styles.emoji}>
{ligado ? '💡' : '🔌'}
</Text>
<Text style={styles.botaoTexto}>
{ligado ? 'LIGADO' : 'DESLIGADO'}
</Text>
</>
)}
</TouchableOpacity>
{erro && (
<Text style={styles.erro}>⚠️ {erro}</Text>
)}
<Text style={styles.rodape}>
Tutorial do Prof. Reginaldo
</Text>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#0f172a',
alignItems: 'center',
justifyContent: 'center',
padding: 20,
},
titulo: {
fontSize: 28,
fontWeight: 'bold',
color: '#22d3ee',
marginBottom: 8,
},
subtitulo: {
fontSize: 16,
color: '#64748b',
marginBottom: 40,
},
botao: {
width: 200,
height: 200,
borderRadius: 100,
alignItems: 'center',
justifyContent: 'center',
shadowColor: '#000',
shadowOffset: { width: 0, height: 4 },
shadowOpacity: 0.3,
shadowRadius: 8,
elevation: 8,
},
botaoLigado: {
backgroundColor: '#22c55e', // Verde
},
botaoDesligado: {
backgroundColor: '#475569', // Cinza
},
emoji: {
fontSize: 60,
marginBottom: 10,
},
botaoTexto: {
fontSize: 18,
fontWeight: 'bold',
color: '#fff',
},
erro: {
color: '#ef4444',
marginTop: 20,
fontSize: 14,
},
rodape: {
position: 'absolute',
bottom: 40,
color: '#475569',
fontSize: 12,
},
});
useState - Estado reativo
const [ligado, setLigado] = useState(false) cria
uma variável ligado e uma função
setLigado para alterá-la. Quando você chama
setLigado(true), a tela atualiza automaticamente!
useEffect - Executar ao carregar
O useEffect executa uma função quando o componente
é carregado. Usamos para buscar o estado inicial do LED assim que o app abre.
TouchableOpacity - Botão tocável
É o "botão" do React Native. O onPress define
o que acontece quando você toca. Ele tem uma animação de opacidade embutida!
🧪 Testando o Sistema Completo
-
1
Inicie o XAMPP (Apache)
A API PHP precisa estar rodando
-
2
Faça upload do código no ESP32
Abra o Monitor Serial para ver o status
-
3
Cole o código no Expo Snack e teste no celular
Use o Expo Go para escanear o QR Code
-
4
Toque no botão e veja o LED acender! 🎉
O comando vai do app → API → ESP32 → LED
🎉 Parabéns! Você criou um sistema IoT completo com controle via aplicativo mobile!
📊 Fluxo de Comunicação
{ "ligado": true }
🏆 Desafios
Mude as cores
Altere as cores do botão ligado/desligado para suas favoritas.
Adicione vibração
Use Vibration.vibrate() do React Native
quando o botão for tocado.
📝 Teste seus Conhecimentos
Quiz Gamificado
Responda às perguntas para ganhar XP e desbloquear a próxima atividade!
Carregando quiz...