
Cómo medir la radiación ultravioleta con la Heltec ESP32 y enviar los datos a ThingSpeak
Nuestra estación meteorológica IoT continúa creciendo.
Después de aprender a medir la temperatura con un LM35 y la iluminación mediante un sensor de luz analógico, incorporamos un nuevo componente muy interesante: el GUVA-S12SD, un sensor capaz de detectar la radiación ultravioleta.
Este tipo de sensores se utiliza en numerosas estaciones meteorológicas y sistemas de monitorización ambiental para conocer la intensidad de la radiación UV y evaluar el riesgo de exposición al Sol.
Material necesario
- Heltec ESP32 WiFi Kit 32 V3.
- Sensor de radiación ultravioleta GUVA-S12SD.
- Sensor de luz analógico.
- Sensor de temperatura LM35.
- Cables Dupont.
- Arduino IDE.
- Cuenta gratuita en ThingSpeak.
Conexión del sensor UV
La conexión es muy sencilla.
| GUVA-S12SD | Heltec ESP32 |
|---|---|
| S | GPIO3 |
| + | 3V3 |
| G | GND |
Los demás sensores permanecen conectados de la siguiente forma:
| Sensor | GPIO |
|---|---|
| LM35 | GPIO1 |
| Sensor de luz | GPIO2 |
Funcionamiento del programa
Cada veinte segundos el programa realiza las siguientes operaciones:
- Lee la temperatura del LM35.
- Lee el nivel de iluminación mediante el sensor de luz.
- Lee la salida analógica del sensor GUVA-S12SD.
- Muestra toda la información en el Monitor Serie.
- Presenta los datos en la pantalla OLED integrada.
- Envía automáticamente los tres valores a ThingSpeak.
Gracias a ello es posible monitorizar simultáneamente tres variables ambientales utilizando una única placa ESP32.
https://github.com/jusevil271/heltec-esp32-iot-tutorials/blob/main/08_heltecluztempuvsinssid.ino
¿Qué mide realmente el GUVA-S12SD?
El GUVA-S12SD no proporciona directamente el Índice UV, sino una tensión analógica proporcional a la radiación ultravioleta recibida.
En este tutorial trabajamos con el valor proporcionado por el sensor para comprobar su funcionamiento.
En un próximo artículo realizaremos una calibración completa, utilizando datos reales de radiación ultravioleta para convertir la tensión medida en un auténtico Índice UV, tal y como hacen las estaciones meteorológicas profesionales.
Visualización en ThingSpeak
Los datos quedan organizados de la siguiente forma:
- Field 1: Temperatura.
- Field 2: Nivel de iluminación.
- Field 3: Radiación UV.
Con ello podemos visualizar gráficas independientes para cada una de las variables y seguir ampliando nuestra estación meteorológica con nuevos sensores en los próximos capítulos.
¿Qué aprenderás?
Con este proyecto aprenderás a:
- Utilizar múltiples entradas analógicas del ESP32.
- Integrar varios sensores en un mismo programa.
- Mostrar información simultáneamente en una pantalla OLED.
- Enviar varios campos a ThingSpeak.
- Diseñar una estación meteorológica IoT modular y ampliable.
Próximo capítulo
En el siguiente tutorial realizaremos la calibración del sensor GUVA-S12SD para obtener el Índice UV real, explicando el procedimiento utilizado en instrumentación científica para convertir una señal analógica en una magnitud física.
#include "Arduino.h"
#include <WiFi.h>
#include <ThingSpeak.h>
#include <Wire.h>
#include "HT_SSD1306Wire.h"
//====================================================
// WIFI
//====================================================
const char* ssid = "";
const char* password = "";
//====================================================
// THINGSPEAK
//====================================================
unsigned long channelID = 3427516;
const char* writeAPIKey = "3V4SYV120EWIIEPQ";
//====================================================
// SENSORES
//====================================================
const int sensorLuz = 2; // GPIO2
const int sensorTemperatura = 1; // GPIO1 (LM35)
const int sensorUV = 3; // GPIO3 (GUVA-S12SD)
//====================================================
// OLED
//====================================================
SSD1306Wire factory_display(
0x3c,
500000,
SDA_OLED,
SCL_OLED,
GEOMETRY_128_64,
RST_OLED
);
//====================================================
WiFiClient client;
//====================================================
void VextON()
{
pinMode(Vext, OUTPUT);
digitalWrite(Vext, LOW);
}
//====================================================
void conectarWiFi()
{
WiFi.disconnect(true);
delay(100);
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
factory_display.clear();
factory_display.drawString(0,0,"Conectando...");
factory_display.display();
Serial.print("Conectando a ");
Serial.println(ssid);
while (WiFi.status() != WL_CONNECTED)
{
delay(500);
Serial.print(".");
}
Serial.println();
Serial.println("WiFi conectado");
Serial.print("IP: ");
Serial.println(WiFi.localIP());
factory_display.clear();
factory_display.drawString(0,0,"WiFi OK");
factory_display.drawString(0,15,WiFi.localIP().toString());
factory_display.display();
}
//====================================================
void setup()
{
Serial.begin(115200);
VextON();
delay(100);
factory_display.init();
factory_display.clear();
factory_display.display();
conectarWiFi();
ThingSpeak.begin(client);
pinMode(sensorLuz, INPUT);
pinMode(sensorTemperatura, INPUT);
pinMode(sensorUV, INPUT);
}
//====================================================
void loop()
{
if (WiFi.status() == WL_CONNECTED)
{
//====================================
// SENSOR DE LUZ
//====================================
int luz = analogRead(sensorLuz);
//====================================
// SENSOR LM35
//====================================
int lecturaLM35 = analogRead(sensorTemperatura);
float voltaje = lecturaLM35 * (3.3 / 4095.0);
float temperatura = voltaje * 100.0;
//====================================
// SENSOR UV
//====================================
int lecturaUV = analogRead(sensorUV);
float voltajeUV = lecturaUV * (3.3 / 4095.0);
//====================================
// MONITOR SERIE
//====================================
Serial.println("-------------------------------------");
Serial.print("Temperatura: ");
Serial.print(temperatura,1);
Serial.println(" °C");
Serial.print("Nivel de luz: ");
Serial.println(luz);
Serial.print("Sensor UV: ");
Serial.println(lecturaUV);
Serial.print("Voltaje UV: ");
Serial.print(voltajeUV,3);
Serial.println(" V");
//====================================
// ENVIAR A THINGSPEAK
//====================================
ThingSpeak.setField(1, temperatura);
ThingSpeak.setField(2, luz);
ThingSpeak.setField(3, lecturaUV);
int codigo = ThingSpeak.writeFields(channelID, writeAPIKey);
//====================================
// OLED
//====================================
factory_display.clear();
if(codigo == 200)
{
Serial.println("Datos enviados correctamente");
factory_display.drawString(0,0,"ThingSpeak OK");
}
else
{
Serial.print("Error: ");
Serial.println(codigo);
factory_display.drawString(0,0,"Error");
factory_display.drawString(50,0,String(codigo));
}
factory_display.drawString(0,14,"Temp:");
factory_display.drawString(42,14,String(temperatura,1)+" C");
factory_display.drawString(0,28,"Luz:");
factory_display.drawString(42,28,String(luz));
factory_display.drawString(0,42,"UV:");
factory_display.drawString(42,42,String(lecturaUV));
// Barra de luz
int anchoBarra = map(luz,0,4095,0,128);
factory_display.drawRect(0,56,128,8);
factory_display.fillRect(0,56,anchoBarra,8);
factory_display.display();
}
else
{
Serial.println("WiFi desconectado");
}
// ThingSpeak gratuito: mínimo 15 segundos
delay(20000);
}




