Documentation

GUVA-S12SD UV Light Intensity Sensor Module for Arduino & ESP32 | ShillehTek Product Manual
Documentation / GUVA-S12SD UV Light Intensity Sensor Module for Arduino & ESP32 | ShillehTek Product Manual

GUVA-S12SD UV Light Intensity Sensor Module for Arduino & ESP32 | ShillehTek Product Manual

Overview

The GUVA-S12SD UV Light Intensity Sensor Module is a compact analog ultraviolet sensor built around the Genicom GUVA-S12SD gallium nitride photodiode. The photodiode responds to light in the 240-370 nm band, which covers the UVB range and most of the UVA range — the same wavelengths used to calculate the solar UV Index. The purple CJMCU-style breakout has just three pins (SIG, GND, VCC), making it one of the simplest ways to add sunlight and UV monitoring to an Arduino, ESP32, or Raspberry Pi Pico project.

The photodiode itself produces only a tiny photocurrent — around 113 nA under a 1 mW/cm² UVA source — far too small for a microcontroller to measure directly. The onboard SGM8521 rail-to-rail op-amp amplifies this current into a clean analog voltage on the SIG pin that rises proportionally with UV intensity. A convenient rule of thumb for sunlight is that the UV Index is approximately the output voltage in millivolts divided by 100, so about 0.5 V corresponds to UV Index 5. Because the output tops out around 1 V even in intense sun, it stays comfortably within the safe input range of 3.3V ADCs.

The module runs on anything from 3.3 V to 5 V, so it pairs directly with the ADC pins on an Arduino, ESP32, or Pico with no level shifting. The Raspberry Pi is the one exception: it has no analog inputs, so you read the sensor through an external ADC such as the ADS1115. Typical projects include UV Index weather stations, sun-exposure loggers and wearables, UV lamp monitors, and automatic sunshade or alert systems.

At a Glance

Operating Voltage
3.3V - 5V DC
Spectral Range
240 - 370 nm (UVA/UVB)
Output
Analog voltage
UV Index Formula
Vout (mV) / 100
Onboard Amplifier
SGM8521 op-amp
Pins
SIG, GND, VCC

Specifications

Parameter Value
Sensing Element GUVA-S12SD gallium nitride Schottky photodiode
Spectral Detection Range 240 - 370 nm (UVB and most UVA)
Peak Responsivity 0.14 A/W at 352 nm
Typical Photocurrent 113 nA at 1 mW/cm² (UVA lamp)
Dark Current 1 nA maximum
Onboard Amplifier SGM8521 rail-to-rail op-amp
Operating Voltage 3.3V - 5V DC
Output Signal Analog voltage, approx. 0.1 V per UV Index point (0 - 1 V in sunlight)
UV Index Conversion UV Index ≈ Vout (mV) / 100
Interface 3-pin header: SIG, GND, VCC
Viewing Angle Approx. 100 degrees
Operating Temperature -30°C to +85°C

Pinout Diagram

The module has three pins. SIG is the amplified analog output — connect it to an ADC input on your board (or to an external ADC on Raspberry Pi). GND connects to ground, and VCC accepts any supply from 3.3 V to 5 V. There are no data buses, addresses, or configuration pins to worry about.

GUVA-S12SD UV sensor module pinout diagram showing SIG (analog output), GND, and VCC pins

Wiring Guide

Arduino Wiring

The GUVA-S12SD connects directly to an Arduino analog pin. Power it from 5V and read SIG on A0 — no level shifting or extra components are needed because the sensor output never exceeds about 1 V.

GUVA-S12SD Pin Arduino Pin
VCC 5V
GND GND
SIG A0
Note: With the default 5V analog reference, the sensor's 0-1 V output only uses about a fifth of the ADC range. That still gives roughly 5 mV per step — plenty for UV Index readings to one decimal place.
Tip: For finer resolution on an Uno or Nano, call analogReference(INTERNAL) to switch to the 1.1V internal reference. The sensor's full output range then spans nearly the entire ADC scale. If you do this, replace 5000.0 with 1100.0 in the millivolt conversion.

ESP32 Wiring

The ESP32 reads the sensor directly on one of its ADC pins. Power the module from the 3.3V rail — the output still reaches about 0.1 V per UV Index point, and it stays well below the 3.3V ADC limit.

GUVA-S12SD Pin ESP32 Pin Details
VCC 3.3V
GND GND
SIG GPIO 34 ADC1_CH6, input-only pin
Warning: If your project uses Wi-Fi, connect SIG to an ADC1 pin (GPIO 32-39). The ADC2 pins are shared with the Wi-Fi radio and return unreliable readings while Wi-Fi is active.
Tip: Set the attenuation to ADC.ATTN_11DB (MicroPython) or leave the Arduino core default so the full 0-3.3V range is available. The ESP32 ADC is noisy by nature — averaging 10-20 samples per reading smooths it out considerably.

Raspberry Pi Wiring

The Raspberry Pi has no analog-to-digital converter on any of its GPIO pins, so it cannot read the SIG output by itself — a GPIO pin only sees digital highs and lows, and the sensor's 0-1 V output will simply read as "low" forever. The standard solution is an ADS1115 16-bit ADC breakout: the sensor connects to the ADS1115, and the ADS1115 talks to the Pi over I2C.

Module Pin Connects To Details
GUVA-S12SD VCC Pin 1 (3.3V) Shared 3.3V rail
GUVA-S12SD GND Pin 6 (GND) Shared ground
GUVA-S12SD SIG ADS1115 A0 Analog input channel 0
ADS1115 VDD Pin 1 (3.3V)
ADS1115 GND Pin 6 (GND)
ADS1115 SDA Pin 3 (GPIO 2) I2C data
ADS1115 SCL Pin 5 (GPIO 3) I2C clock
Warning: Do not wire SIG straight to a Raspberry Pi GPIO pin expecting analog values. It will not damage anything (the output stays around 1 V), but the Pi physically cannot digitize it — you need the ADS1115 (or an MCP3008) in between.
Tip: Enable I2C first with sudo raspi-config (Interface Options > I2C), then run i2cdetect -y 1. The ADS1115 should appear at address 0x48 with its ADDR pin unconnected or tied to GND.

Raspberry Pi Pico Wiring

Unlike the full-size Raspberry Pi, the Pico has a built-in 12-bit ADC, so the sensor connects directly. Power the module from the 3V3(OUT) pin and read SIG on one of the three ADC-capable GPIOs.

GUVA-S12SD Pin Pico Pin Details
VCC 3V3(OUT) (physical pin 36)
GND GND (physical pin 38)
SIG GP26 (physical pin 31) ADC0 input
Note: Only GP26, GP27, and GP28 (ADC0-ADC2) can read analog voltages on the Pico. Any of the three works — just match the channel number in your code.
Tip: Power the sensor from 3V3(OUT) rather than VBUS. The ADC reference is derived from the 3.3V rail, so keeping the sensor on the same rail gives more consistent readings.

Code Examples

Arduino

guva_s12sd_arduino.ino
// GUVA-S12SD UV Sensor - Arduino Example
// SIG Pin: A0, VCC: 5V, GND: GND
// UV Index is approximately the output voltage in mV divided by 100

const int sigPin = A0;
const int numSamples = 16;

void setup() {
  Serial.begin(9600);
}

void loop() {
  // Average several readings to smooth out ADC noise
  long total = 0;
  for (int i = 0; i < numSamples; i++) {
    total += analogRead(sigPin);
    delay(2);
  }
  float raw = total / (float)numSamples;

  // Convert the 10-bit reading (0-1023) to millivolts (5V reference)
  float millivolts = raw * (5000.0 / 1023.0);

  // Approximate solar UV Index: mV / 100
  float uvIndex = millivolts / 100.0;

  Serial.print("Voltage: ");
  Serial.print(millivolts, 0);
  Serial.print(" mV | UV Index: ");
  Serial.println(uvIndex, 1);

  delay(1000);
}

ESP32 (MicroPython)

guva_s12sd_esp32.py
# GUVA-S12SD UV Sensor - ESP32 MicroPython Example
# SIG Pin: GPIO 34 (ADC1_CH6), VCC: 3.3V, GND: GND
# UV Index is approximately the output voltage in mV divided by 100

from machine import ADC, Pin
import time

adc = ADC(Pin(34))        # GPIO 34: input-only pin on ADC1
adc.atten(ADC.ATTN_11DB)  # Full 0-3.3V input range

while True:
    # Average several readings to smooth out ADC noise
    total_uv = 0
    for _ in range(16):
        total_uv += adc.read_uv()  # Factory-calibrated reading in microvolts
        time.sleep_ms(2)
    millivolts = total_uv / 16 / 1000

    # Approximate solar UV Index: mV / 100
    uv_index = millivolts / 100

    print("Voltage: {:.0f} mV | UV Index: {:.1f}".format(millivolts, uv_index))
    time.sleep(1)

Raspberry Pi (Python + ADS1115)

guva_s12sd_rpi.py
#!/usr/bin/env python3
# GUVA-S12SD UV Sensor - Raspberry Pi + ADS1115 Example
# The Pi has no analog inputs, so an ADS1115 reads SIG over I2C.
# SIG -> ADS1115 A0, SDA -> GPIO 2, SCL -> GPIO 3
# Install the library first:
#   pip3 install adafruit-circuitpython-ads1x15

import time
import board
import busio
import adafruit_ads1x15.ads1115 as ADS
from adafruit_ads1x15.analog_in import AnalogIn

# I2C bus on GPIO 2 (SDA) / GPIO 3 (SCL)
i2c = busio.I2C(board.SCL, board.SDA)

# ADS1115 at default address 0x48, sensor SIG on channel A0
ads = ADS.ADS1115(i2c)
ads.gain = 2  # +/-2.048V full scale covers the 0-1V output with headroom
channel = AnalogIn(ads, ADS.P0)

try:
    while True:
        millivolts = channel.voltage * 1000

        # Approximate solar UV Index: mV / 100
        uv_index = millivolts / 100

        print("Voltage: {:.0f} mV | UV Index: {:.1f}".format(millivolts, uv_index))
        time.sleep(1)

except KeyboardInterrupt:
    print("Measurement stopped by user")

Raspberry Pi Pico (MicroPython)

guva_s12sd_pico.py
# GUVA-S12SD UV Sensor - Pico MicroPython Example
# SIG Pin: GP26 (ADC0, physical pin 31), VCC: 3V3(OUT), GND: GND
# UV Index is approximately the output voltage in mV divided by 100

from machine import ADC
import time

adc = ADC(26)             # GP26 = ADC0
CONVERSION = 3.3 / 65535  # read_u16() returns 0-65535 across 0-3.3V

while True:
    # Average several readings to smooth out ADC noise
    total = 0
    for _ in range(16):
        total += adc.read_u16()
        time.sleep_ms(2)
    millivolts = (total / 16) * CONVERSION * 1000

    # Approximate solar UV Index: mV / 100
    uv_index = millivolts / 100

    print("Voltage: {:.0f} mV | UV Index: {:.1f}".format(millivolts, uv_index))
    time.sleep(1)

Frequently Asked Questions

How do I convert the output voltage to a UV Index?
Divide the output voltage in millivolts by 100 — for example, 300 mV corresponds to roughly UV Index 3. This is the widely used approximation for solar UV based on the sensor's response of about 0.1 V per index point. It is an estimate, not a lab-calibrated measurement, so for best accuracy compare your readings against a local weather service UV report on a clear day and scale accordingly.
Can I use this sensor with a Raspberry Pi?
Yes, but not directly. The Raspberry Pi has no analog-to-digital converter, so it cannot read the SIG pin's analog voltage on its own. Add an ADS1115 or MCP3008 ADC: the sensor's SIG connects to the ADC, and the ADC sends digital readings to the Pi over I2C or SPI. The Pico, ESP32, and Arduino all have built-in ADCs and read the sensor directly.
Should I power the module with 3.3V or 5V?
Either works — the module accepts 3.3V to 5V. On 3.3V boards like the ESP32 and Pico, power it from the 3.3V rail so everything shares one supply. Because the output only reaches about 1 V even in intense sunlight, it is safe for 3.3V ADC inputs regardless of which supply voltage you choose.
Why does my sensor read almost zero indoors or behind a window?
That is normal — indoor LED and fluorescent lighting emits almost no UV, and standard window glass blocks nearly all UVB and much of the UVA that the sensor detects. To verify the module works, take it outside into direct sunlight or shine a UV source (such as a 365 nm UV flashlight) at the photodiode. Readings of a few millivolts indoors are expected.
Do I need a library to use this sensor?
No. The module outputs a plain analog voltage, so a single analogRead() on Arduino or an ADC read in MicroPython is all it takes. The only library requirement is on the Raspberry Pi, where you install the ADS1115 driver (adafruit-circuitpython-ads1x15) to read the external ADC over I2C.
Can it detect UVC from germicidal or sterilization lamps?
The photodiode's response starts at 240 nm, so strong UVC sources near that edge will register, but the sensor is designed and scaled for solar UVA/UVB and the mV/100 UV Index formula does not apply to lamp measurements. Treat any lamp reading as a relative indication only. Also remember that UVC sources are hazardous — never expose skin or eyes while testing.
What is the difference between this and a light sensor like the BH1750 or an LDR?
Ordinary light sensors measure visible brightness (lux) and respond to any bright light source. The GUVA-S12SD responds only to the 240-370 nm ultraviolet band and has high visible-light rejection, so a bright LED lamp that reads thousands of lux on a BH1750 barely moves this sensor at all. Use both together if your project needs ambient brightness and UV exposure.

Related Tutorials