ESP32 - GUVA-S12SD UV Sensor

Sunburn does not wait for a hot day. A cool, bright spring morning can carry more UV than a warm cloudy afternoon, and our skin cannot feel the difference. With a GUVA-S12SD UV sensor, an ESP32 can measure that invisible light for you. In this tutorial, the ESP32 first prints the raw ADC number and the calibrated voltage from the sensor, and then turns that voltage into a UV index with a level name, from Low to Extreme, that anyone can understand.

ESP32 GUVA-S12SD UV sensor

This tutorial shows how to program the ESP32 using the Arduino language (C/C++) via the Arduino IDE. If you’d like to learn how to program the ESP32 with MicroPython, visit this ESP32 MicroPython - GUVA-S12SD UV Sensor tutorial.

Introduction to the GUVA-S12SD UV Sensor

GUVA-S12SD UV sensor pinout
image source: diyables.io

The module is a small purple board, about 11mm x 27mm, with two mounting holes so you can fix it inside a box or under a clear lid. Look for the tiny white square on it: that is the GUVA-S12SD UV photodiode. Next to it sits a VLM358 op-amp chip. Here is the idea in one sentence: when UV light falls on the photodiode, it lets a very small current flow, and the op-amp turns that current into a voltage on the SIG pin, which the ESP32 can measure with its ADC. More UV gives a higher voltage. The DIYables version comes with the header already soldered and is sold in a pack of two.

GUVA-S12SD UV Sensor Module
The sensing element GUVA-S12SD UV photodiode
The amplifier VLM358 op-amp, on the board
The light it senses UV-A and UV-B, 240nm to 370nm
The viewing angle 130 degrees
The supply voltage 2.5V to 5V DC
The output analog voltage, about 0V (no UV) to about 1V or more in strong sun
The board size about 11mm x 27mm

GUVA-S12SD UV Sensor Pinout

The three pins are printed on the board in the order SIG, GND, VCC:

  • SIG pin: connect this pin to an ADC pin of the ESP32. Its voltage rises when more UV light reaches the sensor.
  • GND pin: connect this pin to GND (0V).
  • VCC pin: connect this pin to the 3V3 pin of the ESP32.

From voltage to UV index

Most hobby projects use one simple rule: every 0.1V on the SIG pin is about 1 point of UV index. So 0.5V means a UV index of about 5. This is a rough estimate, good enough for a reminder or a fun weather station, but it is not a calibrated UV meter. The UV index scale below comes from the WHO:

UV Index Level What it means
0 to 2 Low little risk for most people
3 to 5 Moderate use sunscreen and a hat around midday
6 to 7 High cover up and look for shade
8 to 10 Very High skin can burn quickly
11 or more Extreme avoid the midday sun

※ NOTE THAT:

Glass windows, LED lamps and fluorescent tubes give almost no UV in the 240nm to 370nm range. So, inside a room, the sensor reads close to 0V, even when the room looks very bright. This is normal. Take the sensor outdoors into direct sunlight, or point a UV flashlight at it, to see real numbers.

What can you build with it? A sunscreen reminder that beeps when the index climbs above 3, a balcony UV index station, a tester that checks if an old UV lamp or UV LED still works, a part of an outdoor weather station, or a smart blind that closes when the sun gets too strong.

Wiring Diagram

The sensor needs only three wires. Both codes in this tutorial use the same wiring:

UV Sensor Module ESP32
SIG → GPIO36 (VP)
GND → GND
VCC → 3V3

GPIO36 belongs to ADC1. This matters: the ADC2 pins stop working when WiFi is on, so an ADC1 pin keeps the project ready for sending UV data to a phone or a web page later.

ESP32 GUVA-S12SD UV sensor wiring diagram

This image is created using Fritzing. Click to enlarge image

If you're unfamiliar with how to supply power to the ESP32 and other components, you can find guidance in the following tutorial: The best way to Power ESP32 and sensors/displays.

How To Program For GUVA-S12SD UV Sensor

No library is needed. The ESP32 core for Arduino IDE already has the two ADC functions we use.

  • Set the ADC range so the pin can read the full output of the sensor:
analogSetAttenuation(ADC_11db);
  • Get the raw ADC number with analogRead(). On the ESP32 it goes from 0 to 4095:
int rawValue = analogRead(36);
  • Get the voltage with analogReadMilliVolts(). This function uses the calibration data stored inside each ESP32 chip, so its result is closer to the real voltage than a simple "raw x 3.3 / 4095" formula:
float voltage = analogReadMilliVolts(36) / 1000.0; // in volts
  • Turn the voltage into an approximate UV index:
float uvIndex = voltage / 0.1;

ESP32 Code - Read the Raw Value and the SIG Voltage

Before thinking about UV index, it is a good idea to see what the sensor really sends. Once per second, this code prints both the raw ADC number and the calibrated SIG voltage, with three decimals.

/* * This ESP32 code is created by esp32io.com * * This ESP32 code is released in the public domain * * For more detail (instruction and wiring diagram), visit https://esp32io.com/tutorials/esp32-guva-s12sd-uv-sensor */ // ESP32 reads the GUVA-S12SD UV sensor module and prints the raw ADC value and the SIG voltage // Wiring: SIG -> GPIO36 (VP, ADC1), GND -> GND, VCC -> 3V3 #define UV_SIG_PIN 36 // ESP32's GPIO36 (ADC1) connected to the SIG pin of the UV sensor void setup() { Serial.begin(9600); analogSetAttenuation(ADC_11db); // let the ADC pin read from 0V up to about 3.1V } void loop() { int rawValue = analogRead(UV_SIG_PIN); // raw ADC value: 0 to 4095 (12-bit) uint32_t milliVolts = analogReadMilliVolts(UV_SIG_PIN); // calibrated voltage in millivolts float sigVoltage = milliVolts / 1000.0; // millivolts -> volts Serial.print("ADC raw: "); Serial.print(rawValue); Serial.print(" | SIG: "); Serial.print(sigVoltage, 3); // 3 decimals, e.g. 0.412 Serial.println(" V"); delay(1000); // one line per second }

Quick Instructions

  • If this is the first time you use ESP32, see how to setup environment for ESP32 on Arduino IDE.
  • Wire the UV sensor to the ESP32 as in one of the diagrams above.
  • Connect the ESP32 to your PC with the USB Type-C cable.
  • Open Arduino IDE and pick your ESP32 board (e.g. ESP32 Dev Module) and the right COM port.
  • Paste the code above into a new sketch.
  • Click to the Upload button to compile the code and send it to the ESP32.
How to upload ESP32 code on Arduino IDE
  • Open the Serial Monitor at 9600 baud.
How to open serial monitor on Arduino IDE
  • Watch a few lines at your desk, then carry the ESP32 (a laptop or a USB power bank helps) to a sunny window that is open, or outside, and point the white square at the sky.
∞
Newbiely | Arduino IDE 2.3.8
──
☐
✕
File
Edit
Sketch
Tools
Help
ESP32 Dev Module
Newbiely.ino
···
8 Serial.println("Hello World!");
Output
Serial Monitor
Message (Enter to send message to 'ESP32 Dev Module' on 'COM15')
New Line
9600 baud
ADC raw: 0 | SIG: 0.011 V ADC raw: 0 | SIG: 0.013 V ADC raw: 0 | SIG: 0.012 V ADC raw: 141 | SIG: 0.197 V ADC raw: 478 | SIG: 0.452 V ADC raw: 690 | SIG: 0.613 V ADC raw: 702 | SIG: 0.621 V ADC raw: 655 | SIG: 0.587 V
Ln 11, Col 1
ESP32 Dev Module on COM15
2

The first three lines were taken indoors: the raw value is 0 and the voltage is only a few millivolts. The ESP32 ADC is not very good at voltages under about 0.1V, so small indoor readings can jump a little or stay at 0. Outdoors, the voltage climbs to a few hundred millivolts. If you still see almost 0V in full sun, check the SIG wire and make sure nothing (glass, plastic, a phone case) covers the sensor.

ESP32 Code - Show the UV Index and Its Level

Now the voltage becomes something useful. To keep the number steady, the code takes 16 readings, averages them, divides the result by 0.1 to get the UV index, and prints it with one decimal next to the WHO level name.

/* * This ESP32 code is created by esp32io.com * * This ESP32 code is released in the public domain * * For more detail (instruction and wiring diagram), visit https://esp32io.com/tutorials/esp32-guva-s12sd-uv-sensor */ // ESP32 turns the GUVA-S12SD UV sensor output into an approximate UV index and a level name // Wiring: SIG -> GPIO36 (VP, ADC1), GND -> GND, VCC -> 3V3 // Note: UV index = SIG voltage / 0.1 is a rough hobby estimate, not a calibrated UV meter #define UV_SIG_PIN 36 // ESP32's GPIO36 (ADC1) connected to the SIG pin of the UV sensor #define SAMPLES 16 // number of readings averaged for each result // read the SIG pin many times and return the average voltage in volts float readUvVoltage() { uint32_t sum = 0; for (int i = 0; i < SAMPLES; i++) { sum += analogReadMilliVolts(UV_SIG_PIN); // calibrated reading in millivolts delay(5); } return (sum / (float)SAMPLES) / 1000.0; // average millivolts -> volts } // return the WHO name for a UV index value const char* uvLevelName(float uvIndex) { if (uvIndex < 3) return "Low"; if (uvIndex < 6) return "Moderate"; if (uvIndex < 8) return "High"; if (uvIndex < 11) return "Very High"; return "Extreme"; } void setup() { Serial.begin(9600); analogSetAttenuation(ADC_11db); // let the ADC pin read from 0V up to about 3.1V } void loop() { float voltage = readUvVoltage(); float uvIndex = voltage / 0.1; // about 1 UV index point for every 0.1V Serial.print("SIG: "); Serial.print(voltage, 2); Serial.print(" V -> UV index: "); Serial.print(uvIndex, 1); // one decimal Serial.print(" ("); Serial.print(uvLevelName(uvIndex)); Serial.println(")"); delay(1000); }

Quick Instructions

  • Keep the same wiring.
  • Paste this code into Arduino IDE and upload it to the ESP32.
  • Open the Serial Monitor at 9600 baud.
  • Start in the shade, then move the sensor into direct sunlight, around midday if you can.
∞
Newbiely | Arduino IDE 2.3.8
──
☐
✕
File
Edit
Sketch
Tools
Help
ESP32 Dev Module
Newbiely.ino
···
8 Serial.println("Hello World!");
Output
Serial Monitor
Message (Enter to send message to 'ESP32 Dev Module' on 'COM15')
New Line
9600 baud
SIG: 0.02 V -> UV index: 0.2 (Low) SIG: 0.09 V -> UV index: 0.9 (Low) SIG: 0.27 V -> UV index: 2.7 (Low) SIG: 0.38 V -> UV index: 3.8 (Moderate) SIG: 0.56 V -> UV index: 5.6 (Moderate) SIG: 0.64 V -> UV index: 6.4 (High) SIG: 0.66 V -> UV index: 6.6 (High) SIG: 0.71 V -> UV index: 7.1 (High)
Ln 11, Col 1
ESP32 Dev Module on COM15
2

Compare your result with the UV index from a weather app for your city. If your sensor reads a bit higher or lower all the time, you can change the 0.1 in the code to match it better. To give the ESP32 a voice, add a buzzer and make it beep above a UV index of 3, as in ESP32 - Piezo Buzzer.

Line-by-line Code Explanation

Both ESP32 codes above have comments on their important lines. Please read the comments in the code!

Video Tutorial

Making video is a time-consuming work. If the video tutorial is necessary for your learning, please let us know by subscribing to our YouTube channel , If the demand for video is high, we will make the video tutorial.

Language References

※ OUR MESSAGES