Envió de datos por GPRS y esp32 a un servidor remoto

 Componentes Necesarios

  • ESP32

  • Módulo SIM800L

  • Sensor DHT11 o DHT22

  • Fuente de alimentación para SIM800L (3.7V-4.2V)

  • Cables y protoboard

???? Esquema de Conexiones

text
ESP32         SIM800L
-----         -------
3.3V    -->   VCC
GND     -->   GND
GPIO16  -->   TX
GPIO17  -->   RX

ESP32         DHT11/DHT22
-----         -----------
3.3V    -->   VCC
GND     -->   GND
GPIO4   -->   DATA

???? Código Arduino IDE

cpp
#include <HardwareSerial.h>
#include <DHT.h>

// Configuración del DHT
#define DHT_PIN 4
#define DHT_TYPE DHT11
DHT dht(DHT_PIN, DHT_TYPE);

// Configuración SIM800L
HardwareSerial sim800(1); // Usar UART2

// Configuración del servidor
const char* SERVER = "tudominio.com";
const char* PATH = "/api/temperatura.php";
const int PORT = 80;

// Variables para datos
float temperatura = 0;
float humedad = 0;

void setup() {
  Serial.begin(115200);
  dht.begin();
  
  // Inicializar SIM800L
  sim800.begin(9600, SERIAL_8N1, 16, 17); // RX=16, TX=17
  
  Serial.println("Iniciando sistema...");
  
  // Configurar módulo GSM
  inicializarGSM();
  
  delay(5000);
}

void loop() {
  // Leer sensor
  leerSensor();
  
  // Enviar datos al servidor
  if (enviarDatosServidor()) {
    Serial.println("Datos enviados correctamente");
  } else {
    Serial.println("Error al enviar datos");
  }
  
  // Esperar 5 minutos antes de la siguiente lectura
  delay(300000);
}

void leerSensor() {
  temperatura = dht.readTemperature();
  humedad = dht.readHumidity();
  
  if (isnan(temperatura) || isnan(humedad)) {
    Serial.println("Error leyendo el sensor DHT");
    temperatura = 0;
    humedad = 0;
    return;
  }
  
  Serial.print("Temperatura: ");
  Serial.print(temperatura);
  Serial.print("°C, Humedad: ");
  Serial.print(humedad);
  Serial.println("%");
}

void inicializarGSM() {
  Serial.println("Configurando módulo GSM...");
  
  // Esperar que el módulo esté listo
  delay(10000);
  
  // Comandos de configuración básicos
  enviarComando("AT", "OK", 5000);
  enviarComando("AT+CPIN?", "READY", 5000);
  enviarComando("AT+CREG?", "0,1", 5000);
  enviarComando("AT+CGATT?", "1", 5000);
  enviarComando("AT+CSQ", "OK", 5000);
  enviarComando("AT+SAPBR=3,1,\"CONTYPE\",\"GPRS\"", "OK", 5000);
  enviarComando("AT+SAPBR=3,1,\"APN\",\"internet\"", "OK", 5000);
  enviarComando("AT+SAPBR=1,1", "OK", 5000);
  enviarComando("AT+HTTPINIT", "OK", 5000);
}

bool enviarComando(String comando, String respuesta, int timeout) {
  Serial.print("Enviando: ");
  Serial.println(comando);
  
  sim800.println(comando);
  
  unsigned long startTime = millis();
  String response = "";
  
  while (millis() - startTime < timeout) {
    if (sim800.available()) {
      char c = sim800.read();
      response += c;
      Serial.write(c);
    }
    
    if (response.indexOf(respuesta) != -1) {
      Serial.println("Comando exitoso");
      return true;
    }
  }
  
  Serial.println("Timeout en comando");
  return false;
}

bool enviarDatosServidor() {
  // Construir los datos POST
  String postData = "temperatura=" + String(temperatura) + 
                   "&humedad=" + String(humedad);
  
  // Configurar HTTP
  String comandoHTTP = "AT+HTTPPARA=\"URL\",\"http://" + String(SERVER) + String(PATH) + "\"";
  if (!enviarComando(comandoHTTP, "OK", 10000)) return false;
  
  // Configurar contenido
  if (!enviarComando("AT+HTTPPARA=\"CONTENT\",\"application/x-www-form-urlencoded\"", "OK", 5000)) return false;
  
  // Configurar tamaño de datos
  String dataLength = "AT+HTTPDATA=" + String(postData.length()) + ",10000";
  if (!enviarComando(dataLength, "DOWNLOAD", 5000)) return false;
  
  // Enviar datos
  sim800.print(postData);
  delay(5000);
  
  // Realizar petición POST
  if (!enviarComando("AT+HTTPACTION=1", "200", 15000)) return false;
  
  // Cerrar HTTP
  enviarComando("AT+HTTPTERM", "OK", 5000);
  
  return true;
}

???? Código PHP para el Servidor

temperatura.php

php
<?php
header('Content-Type: application/json');
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: POST');
header('Access-Control-Allow-Headers: Content-Type');

// Configuración de la base de datos
$servername = "localhost";
$username = "tu_usuario";
$password = "tu_password";
$dbname = "nombre_base_datos";

// Crear conexión
$conn = new mysqli($servername, $username, $password, $dbname);

// Verificar conexión
if ($conn->connect_error) {
    die("Connection failed: " . $conn->connect_error);
}

// Obtener datos POST
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
    $temperatura = isset($_POST['temperatura']) ? floatval($_POST['temperatura']) : null;
    $humedad = isset($_POST['humedad']) ? floatval($_POST['humedad']) : null;
    
    if ($temperatura !== null && $humedad !== null) {
        // Preparar y ejecutar consulta
        $stmt = $conn->prepare("INSERT INTO temperaturas (temperatura, humedad, fecha) VALUES (?, ?, NOW())");
        $stmt->bind_param("dd", $temperatura, $humedad);
        
        if ($stmt->execute()) {
            echo json_encode(array("status" => "success", "message" => "Datos guardados"));
        } else {
            echo json_encode(array("status" => "error", "message" => "Error al guardar"));
        }
        
        $stmt->close();
    } else {
        echo json_encode(array("status" => "error", "message" => "Datos incompletos"));
    }
} else {
    echo json_encode(array("status" => "error", "message" => "Método no permitido"));
}

$conn->close();
?>

????️ Estructura de la Base de Datos MySQL

sql
CREATE DATABASE iot_temperatura;

USE iot_temperatura;

CREATE TABLE temperaturas (
    id INT AUTO_INCREMENT PRIMARY KEY,
    temperatura DECIMAL(4,2) NOT NULL,
    humedad DECIMAL(4,2) NOT NULL,
    fecha DATETIME DEFAULT CURRENT_TIMESTAMP
);

-- Opcional: Crear usuario específico para la aplicación
CREATE USER 'iot_user'@'localhost' IDENTIFIED BY 'password_seguro';
GRANT INSERT, SELECT ON iot_temperatura.temperaturas TO 'iot_user'@'localhost';
FLUSH PRIVILEGES;

???? PHP para Mostrar los Datos

mostrar_datos.php

php
<?php
// Configuración de la base de datos
$servername = "localhost";
$username = "tu_usuario";
$password = "tu_password";
$dbname = "nombre_base_datos";

// Crear conexión
$conn = new mysqli($servername, $username, $password, $dbname);

// Verificar conexión
if ($conn->connect_error) {
    die("Connection failed: " . $conn->connect_error);
}

// Obtener últimos 50 registros
$sql = "SELECT temperatura, humedad, fecha FROM temperaturas ORDER BY fecha DESC LIMIT 50";
$result = $conn->query($sql);
?>

<!DOCTYPE html>
<html>
<head>
    <title>Datos de Temperatura y Humedad</title>
    <style>
        table { border-collapse: collapse; width: 100%; }
        th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }
        th { background-color: #f2f2f2; }
        tr:nth-child(even) { background-color: #f9f9f9; }
    </style>
</head>
<body>
    <h1>Registros de Temperatura y Humedad</h1>
    
    <?php if ($result->num_rows > 0): ?>
        <table>
            <tr>
                <th>Temperatura (°C)</th>
                <th>Humedad (%)</th>
                <th>Fecha y Hora</th>
            </tr>
            <?php while($row = $result->fetch_assoc()): ?>
            <tr>
                <td><?php echo $row["temperatura"]; ?></td>
                <td><?php echo $row["humedad"]; ?></td>
                <td><?php echo $row["fecha"]; ?></td>
            </tr>
            <?php endwhile; ?>
        </table>
    <?php else: ?>
        <p>No hay datos disponibles</p>
    <?php endif; ?>
    
    <?php $conn->close(); ?>
</body>
</html>

⚙️ Configuración Adicional

1. Configuración APN (depende de tu operador)

cpp
// Para Movistar México:
enviarComando("AT+SAPBR=3,1,\"APN\",\"internet.movistar.mx\"", "OK", 5000);

// Para Telcel:
enviarComando("AT+SAPBR=3,1,\"APN\",\"internet.itelcel.com\"", "OK", 5000);

// Para AT&T:
enviarComando("AT+SAPBR=3,1,\"APN\",\"proxy.movil.att.com.mx\"", "OK", 5000);

2. Mejoras del Código

cpp
// Agregar manejo de errores mejorado
void manejarErrorGSM() {
  Serial.println("Reiniciando módulo GSM...");
  // Agregar lógica de reinicio si es necesario
}

// Función para verificar conexión GPRS
bool verificarConexionGPRS() {
  return enviarComando("AT+CGATT?", "1", 5000);
}

???? Solución de Problemas Comunes

  1. SIM800L no responde: Verificar alimentación (usar fuente externa)

  2. Error de conexión GPRS: Verificar APN y saldo de la SIM

  3. Datos incorrectos del sensor: Verificar conexiones del DHT

  4. Error 403 en servidor: Verificar permisos del archivo PHP

Este sistema te permitirá monitorear temperatura y humedad de forma remota usando GSM/GPRS y almacenar los datos en una base de datos MySQL.

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *