Page cover

Termómetro e higrómetros digitales y online con Arduino

Podemos probar de crear un Arduino que envíe información a través de una interfaz web y que, a su vez, guarde información dentro de un servidor Linux.

El Github es el siguiente:

Materiales

  • Placa Arduino con todo

  • 4x cables mín.

  • Termo-higrómetro (DHT)

  • LED

  • Botón switch (single pole double throw, SPDT)

  • 1x resistencia 220 Ohm

  • 1x resistencia 10 kOhm

Esquema

En el diagrama no se reflejan bien los pines usados
Fotografía del circuito real

1r - Termohigrómetro con botón de desconexión

Primeramente empezaremos por diseñar la parte del circuito necesaria para toda la práctica, oseaser el sensor de temperatura y humedad junto con un botón switch con estados encendido/apagado por defecto y un LED que nos indicará ese estado para mayor comodidad.

Para la práctica deberemos tener en cuenta algunas cosas importantes de los componentes:

  • El LED tiene dos pines, el largo que deberá ir conectado a la resistencia y en serie con el puerto y el corto que deberá ir al GND.

LED circuit
  • El botón switch (SPDT) tiene tres pines da igual la orientación o el orden pero:

    • Los pines de los lados serán los dos estados (en nuestro caso encendido/3'3V y apagado/GND)

    • El pin central deberá ir conectado al puerto del Arduino y se conectará a uno u otro circuitos.

SPDT button
  • El termohigrometro (DHT):

    • El pin SDA es un pin de datos, que se utiliza para comunicarse con otros dispositivos. Este debe conectarse por resistencia al VCC que, a su vez, irá conectado al circuito de 3'3.

    • El pin NC (Not Connected Pin) es un tipo de pin que se encuentra en varios paquetes de circuitos integrados. Este pin no debe conectarse a ninguna de las conexiones del circuito.

    Pines
    conexiones

Código y explicación

El código lo puedes encontrar aquí: https://github.com/aviladotgibert/arduino_TempHumOnline/tree/main/Termohigrometro_button

Básicamente lo que hace el cogido es:

  1. Inicializar variables en el setup.

  2. En la función loop:

    1. Revisar el valor del botón switch (que siempre será 1 si tiene electricidad o 0 si no tiene).

    2. Si es positivo, enciende el LED e inicia la función de lectura del sensor que es la llamada "leerTempHum" y muestra un mensaje de información.

    3. Iguala el valor del switch al lastSwitchValue, una variable de control.

    4. Si se apaga el botón, apagará el LED y revisará que la variable de control no sea la misma que el valor del switch (0 en este caso).

2o - Enviar los datos por CSV a Windows

A continuación lo que intentaremos es visualizar los datos a través de terminal (no solo por el monitor en serie del Arduino IDE) y, a partir de estos datos, exportarlo a un archivo de texto.

Ya que el propio monitor serial de Arduino IDE no nos permite exportar los datos, deberemos hacerlo a través de otro terminal, como es el propio Powershell de Windows, Tabby, Putty o como podríamos hacer con interfaces Linux.

En mi caso usaré el siguiente script con el terminal de Powershell en modo administrador (Ctrl+X > Ejecutar Powershell como administrador) :

Código del script
# Configura el puerto serie
$port = new-Object System.IO.Ports.SerialPort COM3,115200,None,8,one
$port.open()

# Abre el archivo para escribir
$filePath = "C:\Users\david\Documents\Arduino\Proyectos\output.csv"
$streamWriter = [System.IO.StreamWriter]::new($filePath, $true)
#Crea la primera linea
$streamWriter.WriteLine("Fecha,Temperatura,Humedad")

try {
    while ($true) {
        # Lee los datos del puerto serie
	$line = $port.ReadLine()
				
	# Muestra los datos en la consola (opcional)
        Write-Host $line  
        
        # Escribe los datos en el archivo
	$currentDateTime = Get-Date -format "yyyy-mm-dd-HH:mm:ss"
	echo $currentDateTime
	#Escribe la fecha actual más la temperatura y humedad separadas por comas
	$csvformat = $currentDateTime + "," + $line
			#$streamWriter.WriteLine($currentDateTime)
			#$streamWriter.WriteLine($line)
	$streamWriter.WriteLine($csvformat) 
        $streamWriter.Flush()
    }
}
catch {
    Write-Host "Se ha producido un error: $_"
}

finally {
    # Cierra el archivo y el puerto serie
    $streamWriter.Close()
    $port.Close()
}

Para ejecutarlo recuerda guardarlo como leerScript.ps1 o .bat. A través del terminal, accede a la carpeta donde se encuentra o pon la ruta absoluta al archivo:

.\leerScript.ps1
#o bien: 
C:\Users\user\Documents\Arduino\leerScript.ps1

El script lee los datos de la conexión, los muestra por consola y los va añadiendo al archivo CSV separado por comas para luego intentar usar esos datos en la interfaz web.

Resultado por terminal

Pulsa Ctrl+C para dejar de escribir el archivo.

La fecha la saca con el comando Get-Date y formateado como tu prefieras, la explicación y ejemplos los he sacado de aquí. He decidido hacerlo así ya que Arduino solo permite sacar la fecha y hora actuales con un módulo específico y es más fácil de esta forma.

CSV abierto con Libreoffice

3o - Interfaz web local

A partir de un tutorial que vi, me pareció interesante ver como poder crear un servidor web con Arduino, encontré un código muy práctico para el tema y decidí probarlo sobre mi placa y con mis parámetros para ver si funcionaba.

Con este tutorial y código no solo se puede crear la web con HTML+CSS sino que también te permite embeber JavaScript e incluso modificar el estado de módulos (como LEDs) por web.

El código lo tienes en el Github: https://github.com/alswnet/NocheProgramacion/tree/master/series/arduino_esp/007_Web_Server_Facil

A priori no he modificado nada, solamente he cambiado los parámetros y quitado el tema de los LEDs.

Solamente ten en cuenta de añadir el archivo data.h con el SSID y la contraseña del Wifi y poner el Monitor serie en 115200 bauds. Al iniciar el monitor debería darte la IP para conectarte al servidor siempre y cuando estés dentro de la misma red.

Dentro del archivo de data.h he añadido el siguiente código de html/css/js:

Código de la página
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Gráfico de Líneas de Temperatura y Humedad</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            text-align: center;
            margin: 20px;
        }

        #csvFileInput {
            margin-bottom: 20px;
        }

        canvas {
            max-width: 100%;
            height: auto;
        }
    </style>
</head>
<body>
    <h1>Gráfico de Líneas de Temperatura y Humedad</h1>
    <input type="file" id="csvFileInput" accept=".csv">
    <canvas id="lineChart"></canvas>

    <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
    <script>
        document.getElementById('csvFileInput').addEventListener('change', handleFileSelect);

        function handleFileSelect(event) {
            const file = event.target.files[0];
            if (file && file.type === 'text/csv') {
                const reader = new FileReader();
                reader.onload = function(e) {
                    const csvData = e.target.result;
                    const parsedData = parseCSV(csvData);
                    createLineChart(parsedData);
                };
                reader.readAsText(file);
            } else {
                alert('Por favor, selecciona un archivo CSV.');
            }
        }

        function parseCSV(data) {
            const lines = data.split('\n');
            const labels = [];
            const temperatureData = [];
            const humidityData = [];

            lines.forEach((line, index) => {
                if (index === 0) return; // Omitir la primera línea si contiene encabezados
                const [label, temperature, humidity] = line.split(',');
                if (label && temperature && humidity) {
                    labels.push(label);
                    temperatureData.push(parseFloat(temperature));
                    humidityData.push(parseFloat(humidity));
                }
            });

            return { labels, temperatureData, humidityData };
        }

        function createLineChart(data) {
            const ctx = document.getElementById('lineChart').getContext('2d');
            new Chart(ctx, {
                type: 'line',
                data: {
                    labels: data.labels,
                    datasets: [
                        {
                            label: 'Temperatura',
                            data: data.temperatureData,
                            borderColor: 'rgba(255, 99, 132, 1)',
                            backgroundColor: 'rgba(255, 99, 132, 0.2)',
                            fill: false
                        },
                        {
                            label: 'Humedad',
                            data: data.humidityData,
                            borderColor: 'rgba(54, 162, 235, 1)',
                            backgroundColor: 'rgba(54, 162, 235, 0.2)',
                            fill: false
                        }
                    ]
                },
                options: {
                    responsive: true,
                    scales: {
                        x: {
                            title: {
                                display: true,
                                text: 'Fecha'
                            }
                        },
                        y: {
                            title: {
                                display: true,
                                text: 'Valor'
                            }
                        }
                    }
                }
            });
        }
    </script>
</body>
</html>

Para el gráfico dinámico he usado la librería de Chart.js, open-source y fácil de usar incluso para mi.

4o - Configurar el arduino por acceso público

Para esta práctica, me he basado en las siguientes guías:

Última actualización