DIY - UV-Light Sensor

Solar radiation in the ultraviolet (UV) spectrum can get hazardous to the skin very quickly. Official weather stations rarely measure the UV-intensity, so we want to measure the UV-light ourselves!

Aim of this lesson

In this lesson we are using an UV-light sensor to detect the amount of solar radiation in the UV-spectrum as power per area (μW / cm²).

Additionally, we convert the measured value to the standardized UV-Index which is easier to comprehend.


  • UV-Light Sensor VEML6070


Ultraviolet "light" is a kind of radiation that is invisible to the human eye. It has a shorter wavelength than visible light, but longer than that of X-rays: The spectrum is defined from 100 nm to 380 nm.

Through absorption of the earth's atmosphere in the ozone layer, the solar radiation in the UV-B spectrum (100 - 300 nm) does barely reach the earth's surface. The less dangerous UV-A radiation (300 - 380 nm) is far less absorbed by the atmosphere.

UV-light intensity is measured in micro-watts per square-centimeter (μW / cm²). Our VEML6070 sensor measures radiation from round about 300 - 400 nm, so it can only detect UV-A radiation (for more precise information, consider the datasheet).


Connect the VEML6070 sensor to the Arduino as shown in the graphic above.


To communicate with the sensor via the I²C bus, we need to import the Wire.h library. We also need some constants that define the sensor's I²C address and some configuration of the sensor. Additionally we define a reference value for the conversion of the measurement to a UV-index.

#include <Wire.h>

#define I2C_ADDR_UV 0x38
// integration times
#define IT_0_5 0x0 // 0.5 T
#define IT_1   0x1 // 1 T
#define IT_2   0x2 // 2 T
#define IT_4   0x3 // 4 T

// reference value: 0.01 W/m^2 corresponds to the UV-index 0.4
float refVal = 0.4;

Now we configure our sensor in the setup() function.

void setup() {

  Wire.write((IT_1<<2) | 0x02);

In the loop() function we define the behaviour of our main program to read out the sensor at an interval:

void loop() {
  byte msb=0, lsb=0; // first and second byte that will be read from the sensor
  uint16_t uv;

  Wire.requestFrom(I2C_ADDR_UV+1, 1); // MSB (read first byte from sensor)
  if(Wire.available()) {
    msb =;

  Wire.requestFrom(I2C_ADDR_UV+0, 1); // LSB (read second byte from sensor)
  if(Wire.available()) {
    lsb =;

  uv = (msb<<8) | lsb; // combine bytes to an integer through a bitshift op

  Serial.print("μW per cm²: ");
  Serial.println(uv, DEC);     // log value as 16bit integer
  Serial.print("UV-Index: ");


Attention: If you compile the program before defining the function getUVI() (see below), you will recieve a error message.

Because we can hardly relate power-per-area measurements in everyday life, we want to convert our measurements to the more widely used UV-index. To do this, we implement a function getUVI():

 * getUVI()
 * expects the measurement value from the UV-sensor as input
 * and returns the corresponding value on the UV-index
float getUVI(int uv) {
  float uvi = refVal * (uv * 5.625) / 1000;
  return uvi;

results matching ""

    No results matching ""