domingo, 18 de junio de 2017

Tutorial #6 ESP8266 - MySQL + PHP en Servidor Local

En este video sobre de IOT (internet de las cosas) explico cómo enviar la temperatura que lee un LM35 a un servidor local Apache usando una HTTP REQUEST con el método POST a un archivo PHP que es el encargado de insertar esa temperatura y otros datos en la base de datos. También explico cómo crear esa base de datos MySQL usando la herramienta phpMyAdmin incluida en el servidor.



enviardatos.php:

<?php
$conexion = mysql_connect("localhost", "root", "root");
mysql_select_db("tutorial", $conexion);
mysql_query("SET NAMES 'utf8'");

$chipid = $_POST ['chipid'];
$temperatura = $_POST ['temperatura'];

mysql_query("INSERT INTO `tutorial`.`tabla` (`id`, `chipId`, `fecha`, `temperatura`) VALUES (NULL, '$chipid', CURRENT_TIMESTAMP, '$temperatura');");

mysql_close();

echo "Datos ingresados correctamente.";
?>

formulario.html:

<!DOCTYPE html>
<html>
<head>
<title>Formulario</title>
</head>
<body>
<form action="enviardatos.php" method="POST">
ChipID:<br>
<input type="text" name="chipid" ><br>
Temperatura:<br>
<input type="text" name="temperatura" ><br>
<input type="submit" name="Enviar" >
</body>
</html>

Código Fuente:

#include <ESP8266WiFi.h>
#include <WiFiClient.h> 

//-------------------VARIABLES GLOBALES--------------------------
int contconexion = 0;

const char *ssid = "----";
const char *password = "----";

unsigned long previousMillis = 0;

char host[48];
String strhost = "192.168.1.115";
String strurl = "/tutorial/enviardatos.php";
String chipid = "";

//-------Función para Enviar Datos a la Base de Datos SQL--------

String enviardatos(String datos) {
  String linea = "error";
  WiFiClient client;
  strhost.toCharArray(host, 49);
  if (!client.connect(host, 80)) {
    Serial.println("Fallo de conexion");
    return linea;
  }

  client.print(String("POST ") + strurl + " HTTP/1.1" + "\r\n" + 
               "Host: " + strhost + "\r\n" +
               "Accept: */*" + "*\r\n" +
               "Content-Length: " + datos.length() + "\r\n" +
               "Content-Type: application/x-www-form-urlencoded" + "\r\n" +
               "\r\n" + datos);           
  delay(10);             
  
  Serial.print("Enviando datos a SQL...");
  
  unsigned long timeout = millis();
  while (client.available() == 0) {
    if (millis() - timeout > 5000) {
      Serial.println("Cliente fuera de tiempo!");
      client.stop();
      return linea;
    }
  }
  // Lee todas las lineas que recibe del servidro y las imprime por la terminal serial
  while(client.available()){
    linea = client.readStringUntil('\r');
  }  
  Serial.println(linea);
  return linea;
}

//-------------------------------------------------------------------------

void setup() {

  // Inicia Serial
  Serial.begin(115200);
  Serial.println("");

  Serial.print("chipId: "); 
  chipid = String(ESP.getChipId());
  Serial.println(chipid); 

  // Conexión WIFI
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED and contconexion <50) { //Cuenta hasta 50 si no se puede conectar lo cancela
    ++contconexion;
    delay(500);
    Serial.print(".");
  }
  if (contconexion <50) {
      //para usar con ip fija
      IPAddress ip(192,168,1,156); 
      IPAddress gateway(192,168,1,1); 
      IPAddress subnet(255,255,255,0); 
      WiFi.config(ip, gateway, subnet); 
      
      Serial.println("");
      Serial.println("WiFi conectado");
      Serial.println(WiFi.localIP());
  }
  else { 
      Serial.println("");
      Serial.println("Error de conexion");
  }
}

//--------------------------LOOP--------------------------------
void loop() {

  unsigned long currentMillis = millis();

  if (currentMillis - previousMillis >= 10000) { //envia la temperatura cada 10 segundos
    previousMillis = currentMillis;
    int analog = analogRead(17);
    float temp = analog*0.322265625;
    Serial.println(temp);
    enviardatos("chipid=" + chipid + "&temperatura=" + String(temp, 2));
  }
}

23 comentarios:

  1. Excelente! Un compacto resumen base para muchos posibles proyectos.
    Muchas gracias!

    ResponderEliminar
  2. Muchas gracias por el tutorial, muy completo, yo lo modifique con el sensor de temperatura y humedad DHT11, espero a alguien le sirva, hay que modificar los php y la base de datos con un nuevo campo humedad

    #include
    #include
    #include

    //-------------------VARIABLES GLOBALES--------------------------
    int contconexion = 0;

    const char *ssid = "gustavo";
    const char *password = "582413gusalgora";
    #define DHTPIN 2
    #define DHTTYPE DHT11
    DHT dht(DHTPIN, DHTTYPE);
    unsigned long previousMillis = 0;

    char host[48];
    String strhost = "192.168.0.104";
    String strurl = "/iot/enviardatos.php";
    String chipid = "";


    //-------Función para Enviar Datos a la Base de Datos SQL--------

    String enviardatos(String datos) {
    String linea = "error";
    WiFiClient client;
    strhost.toCharArray(host, 49);
    if (!client.connect(host, 80)) {
    Serial.println("Fallo de conexion a MySql");
    return linea;
    }

    client.print(String("POST ") + strurl + " HTTP/1.1" + "\r\n" +
    "Host: " + strhost + "\r\n" +
    "Accept: */*" + "*\r\n" +
    "Content-Length: " + datos.length() + "\r\n" +
    "Content-Type: application/x-www-form-urlencoded" + "\r\n" +
    "\r\n" + datos);
    delay(10);

    Serial.print("Enviando datos a SQL...");

    unsigned long timeout = millis();
    while (client.available() == 0) {
    if (millis() - timeout > 5000) {
    Serial.println("Cliente fuera de tiempo!");
    client.stop();
    return linea;
    }
    }
    // Lee todas las lineas que recibe del servidro y las imprime por la terminal serial
    while(client.available()){
    linea = client.readStringUntil('\r');
    }
    Serial.println(linea);
    return linea;
    }

    //-------------------------------------------------------------------------

    void setup() {

    // Inicia Serial
    Serial.begin(115200);
    Serial.println("");

    Serial.print("chipId: ");
    chipid = String(ESP.getChipId());
    Serial.println(chipid);

    // Conexión WIFI
    WiFi.begin(ssid, password);
    while (WiFi.status() != WL_CONNECTED and contconexion <50) { //Cuenta hasta 50 si no se puede conectar lo cancela
    ++contconexion;
    delay(500);
    Serial.print(".");
    }
    if (contconexion <50) {
    //para usar con ip fija
    IPAddress ip(192,168,0,156);
    IPAddress gateway(192,168,0,1);
    IPAddress subnet(255,255,255,0);
    WiFi.config(ip, gateway, subnet);

    Serial.println("");
    Serial.println("WiFi conectado");
    Serial.println(WiFi.localIP());
    }
    else {
    Serial.println("");
    Serial.println("Error de conexion");
    }
    }

    //--------------------------LOOP--------------------------------
    void loop() {

    unsigned long currentMillis = millis();

    if (currentMillis - previousMillis >= 10000) { //envia la temperatura cada 10 segundos
    previousMillis = currentMillis;

    float t = dht.readTemperature();
    float h = dht.readHumidity();
    if (isnan(h) || isnan(t)) {
    Serial.println("Falla al leer el sensor DHT11!");
    return;
    }
    Serial.println(t);
    Serial.println(h);
    enviardatos("chipid=" + chipid + "&temperatura=" + String(t, 2) + "&humedad=" + String(h, 2));
    }
    }

    ResponderEliminar
  3. Este comentario ha sido eliminado por el autor.

    ResponderEliminar
    Respuestas
    1. Muchas gracias por tu aporte Gustavo. Fijate que pasaste el usuario y contraseña del WIFI.

      Eliminar
  4. Este comentario ha sido eliminado por el autor.

    ResponderEliminar
  5. Una pregunta el tipo de datos de la DB debe ser igual al tipo de dato que se va a enviar? Quiero probarlo con un led que prende y apaga 1 y 0, convertirlo a string para que solo sea 1 en texto pero al mandarlo dice "fallo de conexion" te mando el LOOP, el insert de DB y el tipo de dato al que quiero enviar.


    void loop() {

    unsigned long currentMillis = millis();

    if (currentMillis - previousMillis >= 10000) {
    previousMillis = currentMillis;
    int a=0;

    digitalWrite(leda,HIGH);
    a=digitalRead(4);
    delay(1000);
    digitalWrite(leda,LOW);
    delay(1000);
    Serial.println(a);
    enviardatos("chipid=" + chipid + "&click=" + String(a));
    }


    ////INSERT

    $chipid = $_POST['chipid'];
    $click=$_POST['click'];


    $insertar="INSERT INTO `cosos`.`mee` (`noact`, `chipid`, `estado`, `fecha`) VALUES (NULL, '$chipid', '$click', CURRENT_TIMESTAMP);";

    //// BD tipo de dato de estado

    estado varchar(50);

    ResponderEliminar
    Respuestas
    1. Todos los datos se deben mandar como string, después la base de datos le da el formato. Lo de fallo de conexión no tiene nada que ver con eso, eso significa que no te estas pudiendo conectar al host, fíjate si poniendo la IP del host en un navegador te podés conectar, si no es así es porque seguramente tenés algún problema con un permiso. ¿ Qué servidor estás usando?

      Eliminar
    2. entonces el formato no importa, solo se convierte en caso de requerirlo. Estoy usando xampp, y sigo peleandome con eso ja

      Eliminar
    3. Ya funciono!!!!!!! me equivoque en la Dir IP del host con la direccion IP del modulo, tube que entrar al modem para saber la direccion de ambos dispositivos!!!!!
      Cuento mis experiencias!

      Eliminar
  6. Este comentario ha sido eliminado por el autor.

    ResponderEliminar
  7. Hola buenas noches, antes que nada gracias por compartir ese tipo de conocimiento. Tengo un problema, no lo he podido solucionar, espero me puedas ayudar, lo que pasa es que al momento de querer enviar los datos de un DHT11 supuestamente se envían. Y al momento de revisar la bd no hay ningún dato guardado. Todo está bien, cuando ingreso un dato por medio del formulario se envía correctamente, pero cuando envíar los datos desde el node mcu no lo hace. Adjunto el archivo Insert.php.
    -----INSERT
    $hostDb="localhost";
    $usuario="root";
    $nombreDb="project";
    $clave="";
    $conexion=mysqli_connect($hostDb, $usuario, $clave, $nombreDb);
    $Temperatura = $_POST ['temperatura'];
    $Humedad = $_POST ['humedad'];
    $query = "INSERT INTO datos1(`Temperatura`, `Humedad` , `Fecha`)
    VALUES('$Temperatura','$Humedad', CURRENT_TIMESTAMP)";
    mysqli_query($conexion, $query);
    mysqli_close($conexion);
    echo "Datos ingresados correctamente";
    ---------
    Código Arduino.
    #include
    #include
    #include
    int TempHum= D4;
    int Temp, Hum;
    int contconexion= 0;
    DHT dht (TempHum,DHT11);
    const char* ssid = "xx";
    const char* password = "xx";
    unsigned long previousMillis = 0;
    char host[48];
    String strhost = "xx-xx-xx-xx";//ip de mi computadora
    String strurl = "/Project/Insert.php";
    //String chipid = "";
    //-------Función para Enviar Datos a la Base de Datos SQL--------
    String enviardatos(String datos) {
    String linea = "Error";
    WiFiClient client;
    strhost.toCharArray(host, 49);
    if (!client.connect(host, 80)) {
    Serial.println("Fallo de conexion a MySql");
    return linea;
    }
    client.print(String("POST ") + strurl + " HTTP/1.1" + "\r\n" +
    "Host: " + strhost + "\r\n" +
    "Accept: */*" + "*\r\n" +
    "Content-Length: " + datos.length() + "\r\n" +
    "Content-Type: application/x-www-form-urlencoded" + "\r\n" +
    "\r\n" + datos);
    delay(10);
    Serial.print("Enviando datos a Base de datos...");
    unsigned long timeout = millis();
    while (client.available() == 0) {
    if (millis() - timeout > 5000) {
    Serial.println("Cliente fuera de tiempo!");
    client.stop();
    return linea;
    }
    }
    // Lee todas las lineas que recibe del servidor y las imprime por la terminal serial
    while(client.available()){
    linea = client.readStringUntil('\r');
    }
    Serial.println(linea);
    return linea;
    }
    //-------------------------------------------------------------------------
    void setup() {
    // Inicia Serial
    Serial.begin(115200);
    Serial.println("");

    Serial.print("Iniciando ");
    //chipid = String(ESP.getChipId());
    //Serial.println(chipid);
    // Conexión WIFI
    WiFi.begin(ssid, password);
    while (WiFi.status() != WL_CONNECTED and contconexion <50) { //Cuenta hasta 50 si no se puede conectar lo cancela
    ++contconexion;
    delay(500);
    Serial.print(".");
    }
    if (contconexion <50) {
    //para usar con ip fija
    IPAddress ip(192,168,1,156);
    IPAddress gateway(192,168,1,1);
    IPAddress subnet(255,255,255,0);
    WiFi.config(ip, gateway, subnet);

    Serial.println("");
    Serial.println("WiFi conectado");
    Serial.println(WiFi.localIP());
    }
    else {
    Serial.println("");
    Serial.println("Error de conexion");
    }
    }

    //--------------------------LOOP--------------------------------
    void loop() {

    unsigned long currentMillis = millis();

    if (currentMillis - previousMillis >= 10000) { //envia la temperatura cada 10 segundos
    previousMillis = currentMillis;


    Hum= dht.readHumidity();
    Temp= dht.readTemperature();

    Serial.print("Temperatura: ");
    Serial.println(Temp);
    Serial.print("Humedad: ");
    Serial.println(Hum);
    Serial.println();

    enviardatos("temperatura=" + String(Temp, 2)+ "&humedad="+ String(Hum,2));
    }
    }
    ¿Tiene que ver que esté usando xampp? Revisé muchas veces el código y no encuentro el error, espero me puedas ayudar, saludos.

    ResponderEliminar
    Respuestas
    1. Pueden ser varias cosas, si funciona desde el formulario genial, eso significa que vas por buen camino. Lo primero que tenés que hacer es ver si funciona el formulario desde un dispositivo de la red lan, que no sea en el que está el servidor, por ejemplo, podés usar un smartphone conectado por wifi.

      ¿Cuál es la IP de tu computadora que pusiste como "xx-xx-xx-xx"?, esa ip no hace falta que la ocultes es una ip de la lan, nadie te va a hacker nada con ese dato. Saludos.

      Eliminar
    2. Hola, gracias por tu respuesta, ya hice la prueba ingresando desde mi celular a la ip donde tengo instalado xampp: 192.168.1.68/Testeo.html (Carga sin ningún problema)
      La ip que tengo en strhost es= 192.168.1.68.

      ¿Será que el problema está en el POST? Aunque a decir verdad, yo veo que no hay error en el código de arduino, saludos.

      Eliminar
    3. Si puede ser un problema del POST Resquest, te recomiendo que veas “Tutorial #9 ESP8266 - MySQL + PHP en Servidor EXTERNO”, ahí explico cómo solucionar el problema del POST Resquest. Pasame el código de Testeo.html , así lo comparo con el código de Arduino para ver si hay algún error. También re recomendaría que uses el servidor que yo recomiendo Uniform Server Coral 8.92 , así descartamos que no sea problema de Xamp, te todas formas debería funcionar con Xamp, en el canal de Ioticos usan Xamp. Saludos.

      Eliminar
  8. excelente video ojala me sirva para lo que necesito gracias :)

    ResponderEliminar
    Respuestas
    1. Muchas gracias. Te recomiendo los videos sobre MQTT, es una solución mas elegante.

      Eliminar
    2. gracias, los estare viendo :)

      Eliminar
  9. buenas noches estoy realizando proyecto Internet de las cosas con servidor xampp y arduino esp8266 el codigo arduino corre y wifi esta conectado pero medice fallo de conexion, y la base de datos manual funciona, necesito ayuda,

    ResponderEliminar
  10. “Fallo de conexión” significa que no se está conectando al host a muchas cosas, por ejemplo que no permita las conexiones externas, es decir desde la PC que tenés instalado Xampp funciona porque lo llamas desde localhost, fíjate si funciona llamándolo desde la IP. Fijate los comentarios de más arriba que tuvieron un problema parecido.

    ResponderEliminar