Estación Meteorológica usando mySQL en servidor. http://calmattj.com

Wemos D1 Mini

Wemos D1 mini GPIO pins

Código

/*
  DHT sensor data to SQL in http://calmattj.com
  Noviembre 2019
  Version 5  
  Scrip que permite subir a una tabla de mySQL en la nube, datos relacionados con la temperatura,
  humedad, iluminacion (lux) en la habitacion, asi como, humedad de la tierra en la 
  maceta de la planta.
*/

// Loading libraries
#ifdef ESP32
  #include <WiFi.h>
  #include <HTTPClient.h>
#else
  #include <ESP8266WiFi.h>
  #include <ESP8266HTTPClient.h>
  #include <WiFiClient.h>
#endif
#include "DHT.h"
#define DHTTYPE DHT11  // Definiendo el tipo de sensor DHT 11
#define DHTPIN 4       // Digital pin connected to the DHT sensor. Conecta a D2
#define SOILPIN 5      // Digital pin connected to soil humidity probe. Conecta a D1
#define LIGHTPIN A0    // Analog pin connected to photolight resistor

DHT dht(DHTPIN, DHTTYPE);

// REPLACE THOSE VARIABLES WITH YOUR SSID and PASSWORD
const char* ssid = "Mi red WiFi";
const char* password = "Tu Password";

os_esp.php";

// Keep this API Key value to be compatible with the PHP code if change the apiKeyValue
// the PHP file needs to have the same key.
String apiKeyValue = "Aqui va un API string";

// REPLACE with your Domain name and URL path or IP address with path
const char* serverName = "http://calmattj.com/post_datos_esp.php";


//Declaracion de variables
String sensor = "DHT 11";
String  location = "Oficina_1"; //Esta etiqueta debe cambiar dependiendo del lugar donde se ubica el sensor
int lightValue = 0;        // variable to store the value coming from the sensor
int humidityValue = 0;
int photocellReading;
int LEDpin = 13;          // connect LED to pin D7 (PWM pin)
int LEDbrightness;        //
int lightLED = 14;        // Conectar LED al pin D5 (PWM pin)
float iluminacion; 


void setup() {
  Serial.begin(115200);
  dht.begin();
  pinMode(lightLED, OUTPUT); 
  // Configurar WiFi
  WiFi.begin(ssid, password);
  Serial.println("Connecting");
  while(WiFi.status() != WL_CONNECTED) { 
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.print("Connected to WiFi network with IP Address: ");
  Serial.println(WiFi.localIP());
}

void loop() {
  lightValue = analogRead(LIGHTPIN);
  iluminacion = map(lightValue, 0,1024,10000 , 10 );
  humidityValue = digitalRead(SOILPIN);
   
  //humidityValue = humidityValue + analogRead(SOILPIN); 
  //humidityValue = humidityValue/100.0; 
  // LED gets brighter the darker it is at the sensor
  // that means we have to -invert- the reading from 0-1023 back to 1023-0
  // photocellReading = 1023 - photocellReading;
  //now we have to map 0-1023 to 0-255 since thats the range analogWrite uses
  //LEDbrightness = map(photocellReading, 0, 1023, 0, 255);
  //analogWrite(LEDpin, LEDbrightness);
  
  // Reading temperature or humidity takes about 250 milliseconds!
  // Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
  float h = dht.readHumidity();
  // Read temperature as Celsius (the default)
  float t = dht.readTemperature();
  // Read temperature as Fahrenheit (isFahrenheit = true)
  float f = dht.readTemperature(true);
  
  // Check if any reads failed and exit early (to try again).
  if (isnan(h) || isnan(t) || isnan(f)) {
    Serial.println(F("Failed to read from DHT sensor!"));
    return;
  }

  // Compute heat index in Fahrenheit (the default)
  float hif = dht.computeHeatIndex(f, h);
  // Compute heat index in Celsius (isFahreheit = false)
  float hic = dht.computeHeatIndex(t, h, false);

  Serial.print(location);
  Serial.print(sensor);
  Serial.print(F("Humidity: "));
  Serial.print(h);
  Serial.print(F("%  Temperature: "));
  Serial.print(t);
  Serial.print(F("°C "));
  Serial.print(f);
  Serial.print(F("°F  Heat index: "));
  Serial.print(hic);
  Serial.print(F("°C "));
  Serial.print(hif);
  Serial.println(F("°F"));
  Serial.print(lightValue);
  Serial.println("   ");
  Serial.print("Light reading = ");
  Serial.print(iluminacion);     
  Serial.print(" lux ");
  Serial.println("  ");
  Serial.print("Humidity value = ");
  Serial.print(humidityValue);
  
  if (iluminacion <= 10000 & photocellReading >= 2000) {
    Serial.println("");
    Serial.print("Buenos Dias");
    digitalWrite(lightLED,LOW);
    Serial.println("");
  }
  else {
    Serial.println("");
    Serial.print("Buenas Noches");
    digitalWrite(lightLED,HIGH);
    Serial.println("");
  }

  if (humidityValue != 0) {
    Serial.println("");
    Serial.print("No hay necesidad de regar");
    Serial.println("");
  }
  else {
    Serial.println("");
    Serial.print("Hay que regar la planta");
    Serial.println("");
  }
  
  //Check WiFi connection status
  if(WiFi.status()== WL_CONNECTED){ 
    HTTPClient http;
    
    // Your Domain name with URL path or IP address with path
    http.begin(serverName);
    
    // Specify content-type header
    http.addHeader("Content-Type", "application/x-www-form-urlencoded");
    
    // Prepare your HTTP POST request data
    String httpRequestData = "api_key=" + apiKeyValue
                           + "&sensor=" + sensor
                           + "&location=" + location
                           + "&value1=" + String(t)
                           + "&value2=" + String(h) 
                           + "&value3=" + String(hic)
                           + "&value4=" + String(hif) 
                           + "&value5=" + String(f)
                           + "&value6=" + String(humidityValue)
                           + "&value7=" + String(iluminacion)
                           + "";
                           
    Serial.print("httpRequestData: ");
    Serial.println(httpRequestData);
    
    // You can comment the httpRequestData variable above
    // then, use the httpRequestData variable below (for testing purposes without the BME280 sensor)
    //String httpRequestData = "api_key=tPmAT5Ab3j7F9&value1=24.75&value2=49.54&value3=1005.14";

    // Send HTTP POST request
    int httpResponseCode = http.POST(httpRequestData);
     
    // If you need an HTTP request with a content type: text/plain
    //http.addHeader("Content-Type", "text/plain");
    //int httpResponseCode = http.POST("Hello, World!");
    
    // If you need an HTTP request with a content type: application/json, use the following:
    //http.addHeader("Content-Type", "application/json");
    //int httpResponseCode = http.POST("{\"value1\":\"19\",\"value2\":\"67\",\"value3\":\"78\"}");
    
    if (httpResponseCode>0) {
      Serial.print("HTTP Response code: ");
      Serial.println(httpResponseCode);
    }
    else {
      Serial.print("Error code: ");
      Serial.println(httpResponseCode);
    }
    // Free resources
    http.end();
  }
  else {
    Serial.println("WiFi Disconnected");
  }
  //Send an HTTP POST request every 30 seconds
  delay(60000);  // Captura un dato cada 60 seg (1 Min)
}

Código de PHP para capturar los valores de las variables en la base de datos mySQL.

<?php

/*
  Jorge Herrera
  Este script es una adaptación del que publica Rui Santos en Random Nerd
  
*/

$servername = "localhost";

// REPLACE with your Database name
$dbname = "MI BASE DE DATOS";
// REPLACE with Database user
$username = "NOMBRE";
// REPLACE with Database user password
$password = "PASSWORD";

// Keep this API Key value to be compatible with the ESP32 code provided in the project page. 
// If you change this value, the ESP32 sketch needs to match
$api_key_value = "ESTE VALOR ES EL MISMO QUE EN EL CODIGO FUENTE";

$api_key = $sensor = $location = $value1 = $value2 = $value3 = $value4 = $value5 = $value6 = $value7 = "";

if ($_SERVER["REQUEST_METHOD"] == "POST") {
    $api_key = test_input($_POST["api_key"]);
    if($api_key == $api_key_value) {
        $sensor = test_input($_POST["sensor"]);
        $location = test_input($_POST["location"]);
        $value1 = test_input($_POST["value1"]);
        $value2 = test_input($_POST["value2"]);
        $value3 = test_input($_POST["value3"]);
        $value4 = test_input($_POST["value4"]);
        $value5 = test_input($_POST["value5"]);
        $value6 = test_input($_POST["value6"]);
        $value7 = test_input($_POST["value7"]);
        
        // Create connection
        $conn = new mysqli($servername, $username, $password, $dbname);
        // Check connection
        if ($conn->connect_error) {
            die("Connection failed: " . $conn->connect_error);
        } 
        
        $sql = "INSERT INTO NewSensorData (sensor, location, value1, value2, value3, value4, value5, value6, value7)
        VALUES ('" . $sensor . "', '" . $location . "', '" . $value1 . "', '" . $value2 . "', '" . $value3 . "', '" . $value4 . "', '" . $value5 . "','" . $value6 . "','" . $value7 . "')";
        
        if ($conn->query($sql) === TRUE) {
            echo "New record created successfully";
        } 
        else {
            echo "Error: " . $sql . "<br>" . $conn->error;
        }
    
        $conn->close();
    }
    else {
        echo "Wrong API Key provided.";
    }

}
else {
    echo "No data posted with HTTP POST.";
}

function test_input($data) {
    $data = trim($data);
    $data = stripslashes($data);
    $data = htmlspecialchars($data);
    return $data;
}

Midiendo la Luz

Es posible medir la intensidad de luz a partir de una foto-celda expuesta, se puede decir que a medida que se incrementa la luz la resistencia de la foto-celda disminuye y cuando hay una menor cantidad la resistencia aumenta. Para verlo gráficamente observemos la siguiente imagen.

La gráfica representa aproximadamente la resistencia del sensor a diferentes niveles de iluminación, observe que cuando los niveles de luz son bajos a resistencia puede llegar a la 10MΩ. Se puede ver que la medida internacional para la iluminación es el lux. Note que la gráfica no es lineal es una log – log.

Un lux (simbolo: lx) es la unidad del sistema internacional de medidas derivada de la luminiscencia. Es igual a un lumen por metro cuadrado. En fotometria, es la medida de la intensidad percibida por el ojo humano de la cantidad de luz que impacta a dicha superficie. Análogamente en radiometria la unidad es Watts por metro cuadrado, donde los Watts son una medida de potencia de los rayos que impactan una superficie.

Valores de lx para diferentes condiciones.

Para ver los valores que se van guardando se creo una tabla en mySQL de mi servidor con la siguiente liga http://calmattj.com/esp-chart.php

Código para ver la gráfica en php.

<!--
  Este código es una adaptación del presentado en el sitio Random Nerd de Rui Santos.
-->
<?php
$servername = "localhost";
// REPLACE with your Database name
$dbname = "MI BASE DE DATOS";
// REPLACE with Database user
$username = "NOMBRE";
// REPLACE with Database user password
$password = "PASSWORD";
// Create connection
$conn = new mysqli($servername, $username, $password, $dbname);
// Check connection
if ($conn->connect_error) {
    die("Connection failed: " . $conn->connect_error);
} 
$sql = "SELECT id, sensor, location, value1, value2, value3, value4, value5, value6, value7, reading_time FROM NewSensorData order by reading_time desc limit 60";

$result = $conn->query($sql);
while ($data = $result->fetch_assoc()){
    $sensor_data[] = $data;
}

$readings_time = array_column($sensor_data, 'reading_time');

// ******* Uncomment to convert readings time array to your timezone ********
$i = 0;
foreach ($readings_time as $reading){
    // Uncomment to set timezone to - 1 hour (you can change 1 to any number)
    $readings_time[$i] = date("Y-m-d H:i:s", strtotime("$reading - 2 hours"));
    // Uncomment to set timezone to + 4 hours (you can change 4 to any number)
    //$readings_time[$i] = date("Y-m-d H:i:s", strtotime("$reading + 4 hours"));
    $i += 1;
}
$loctn = json_encode(array_reverse(array_column($sensor_data,'location')));
$value1 = json_encode(array_reverse(array_column($sensor_data, 'value1')), JSON_NUMERIC_CHECK);
$value2 = json_encode(array_reverse(array_column($sensor_data, 'value2')), JSON_NUMERIC_CHECK);
$value3 = json_encode(array_reverse(array_column($sensor_data, 'value3')), JSON_NUMERIC_CHECK);
$value7 = json_encode(array_reverse(array_column($sensor_data, 'value7')), JSON_NUMERIC_CHECK);
$reading_time = json_encode(array_reverse($readings_time), JSON_NUMERIC_CHECK);
/*
echo $loctn;
echo $value1;
echo $value2;
echo $value3;
echo $value7;
echo $reading_time;
*/
$result->free();
$conn->close();
?>

<!DOCTYPE html>
<html>
<meta name="viewport" content="width=device-width, initial-scale=1">
  <script src="https://code.highcharts.com/highcharts.js"></script>
  <style>
    body {
      min-width: 310px;
      max-width: 1280px;
      height: 500px;
      margin: 0 auto;
    }
    h2 {
      font-family: Arial;
      font-size: 2.5rem;
      text-align: center;
    }
  </style>
  
  
<body>
    <h1 align=center> ESP Weather Station </h1>
    <div id="chart-humedad" class="container"></div>
    <div id="chart-temperatura" class="container"></div>
    <div id="chart-HeatIndx" class="container"></div>
    <div id="chart-lightIndx" class="container"></div>
    
<script>


var value1 = <?php echo $value1; ?>;
var value2 = <?php echo $value2; ?>;
var value3 = <?php echo $value3; ?>;
var value7 = <?php echo $value7; ?>;
var reading_time = <?php echo $reading_time; ?>;

var chartT = new Highcharts.Chart({
  chart:{ renderTo : 'chart-humedad' },
  title: { text: 'DHT11 Humedad' },
  series: [{
    showInLegend: false,
    data: value2
  }],
  plotOptions: {
    line: { animation: false,
      dataLabels: { enabled: true }
    },
    series: { color: '#059e8a' }
  },
  xAxis: { 
    type: 'datetime',
    categories: reading_time
  },
  yAxis: {
    title: { text: 'Humidity (%)' }
    //title: { text: 'Temperature (Fahrenheit)' }
  },
  credits: { enabled: false }
});

var chartH = new Highcharts.Chart({
  chart:{ renderTo:'chart-temperatura' },
  title: { text: 'DHT11 Temperatura (C)) ' },
  series: [{
    showInLegend: false,
    data: value1
  }],
  plotOptions: {
    line: { animation: false,
      dataLabels: { enabled: true }
    }
  },
  xAxis: {
    type: 'datetime',
    //dateTimeLabelFormats: { second: '%H:%M:%S' },
    categories: reading_time
  },
  yAxis: {
    title: { text: 'Temperatura (C)' }
  },
  credits: { enabled: false }
});


var chartP = new Highcharts.Chart({
  chart:{ renderTo:'chart-HeatIndx' },
  title: { text: 'DHT11 HeatIndex (C)' },
  series: [{
    showInLegend: false,
    data: value3
  }],
  plotOptions: {
    line: { animation: false,
      dataLabels: { enabled: true }
    },
    series: { color: '#18009c' }
  },
  xAxis: {
    type: 'datetime',
    categories: reading_time
  },
  yAxis: {
    title: { text: 'Heat Index (C)' }
  },
  credits: { enabled: false }
});

var chartT = new Highcharts.Chart({
  chart:{ renderTo : 'chart-lightIndx' },
  title: { text: 'luminosidad' },
  series: [{
    showInLegend: false,
    data: value7
  }],
  plotOptions: {
    line: { animation: false,
      dataLabels: { enabled: true }
    },
    series: { color: '#059e8a' }
  },
  xAxis: { 
    type: 'datetime',
    categories: reading_time
  },
  yAxis: {
    title: { text: 'Luminosidad' }
    //title: { text: 'Temperature (Fahrenheit)' }
  },
  credits: { enabled: false }
});


</script>
</body>
</html>