2021-01-29 06:31:58 -05:00
[![Arduino CI ](https://github.com/RobTillaart/ML8511/workflows/Arduino%20CI/badge.svg )](https://github.com/marketplace/actions/arduino_ci)
2021-11-09 14:05:19 -05:00
[![Arduino-lint ](https://github.com/RobTillaart/ML8511/actions/workflows/arduino-lint.yml/badge.svg )](https://github.com/RobTillaart/ML8511/actions/workflows/arduino-lint.yml)
[![JSON check ](https://github.com/RobTillaart/ML8511/actions/workflows/jsoncheck.yml/badge.svg )](https://github.com/RobTillaart/ML8511/actions/workflows/jsoncheck.yml)
2021-01-29 06:31:58 -05:00
[![License: MIT ](https://img.shields.io/badge/license-MIT-green.svg )](https://github.com/RobTillaart/ML8511/blob/master/LICENSE)
[![GitHub release ](https://img.shields.io/github/release/RobTillaart/ML8511.svg?maxAge=3600 )](https://github.com/RobTillaart/ML8511/releases)
2021-11-09 14:05:19 -05:00
2020-11-27 05:20:37 -05:00
# ML8511
2022-11-17 14:12:05 -05:00
Arduino library for the ML8511 UV sensor.
2020-11-27 05:20:37 -05:00
2021-05-28 07:39:01 -04:00
2020-11-27 05:20:37 -05:00
## Warning
2021-11-09 14:05:19 -05:00
**Always take precautions as UV radiation can cause sunburn, eye damage and other problems**.
Do not expose yourself to the sun as UV source too long.
When using artificial UV light (TL LED laser a.o.) use appropriate shielding.
2020-02-17 11:22:11 -05:00
2021-05-28 07:39:01 -04:00
2020-02-17 11:22:11 -05:00
## Description
ML8511 - UV sensor - library for Arduino UNO.
2022-11-17 14:12:05 -05:00
- 3V3 Sensor so do **NOT** connect to 5V directly.
- do not forget to connect the EN to either an enablePIN or to 3V3 (constantly enabled).
2021-05-28 07:39:01 -04:00
2023-02-18 14:42:39 -05:00
#### Related
- https://github.com/RobTillaart/TSL235R pulse based irradiance variant.
- https://github.com/RobTillaart/TSL260R analog IR irradiance variant.
- https://github.com/RobTillaart/AnalogUVSensor
- https://github.com/RobTillaart/ML8511 UV sensor
2022-11-17 14:12:05 -05:00
#### Breakout
2020-02-17 11:22:11 -05:00
```
2022-11-17 14:12:05 -05:00
// +-------+--+
// VIN |o +-+| mounting hole
// 3V3 |o +-+|
// GND |o |
// OUT |o |
// EN |o S | Sensor
// +----------+
2020-02-17 11:22:11 -05:00
```
2021-05-28 07:39:01 -04:00
2020-02-17 11:22:11 -05:00
## Operational
As the sensor / breakout is 3V3 one need to connect to Arduino 3V3.
2021-11-09 14:05:19 -05:00
The library converts the **analogRead()** to voltages, and it uses a
2020-02-17 11:22:11 -05:00
reference of 5.0 Volt == 1023 steps as default.
2023-02-18 14:42:39 -05:00
If one wants to use another ratio e.g. 3.3 volts == 4095 steps, one
2021-11-09 14:05:19 -05:00
can set those with **setVoltagePerStep()** .
2020-02-17 11:22:11 -05:00
2022-11-17 14:12:05 -05:00
```cpp
2020-02-17 11:22:11 -05:00
ML8511 light(A0, 7);
light.setVoltagePerStep(3.3, 4095);
```
2021-11-09 14:05:19 -05:00
It is possible to always enable the sensor by connecting the EN pin to 3V3.
2021-06-20 03:13:49 -04:00
The value of the enablePin in the constructor should then be omitted
2022-11-17 14:12:05 -05:00
or set to a negative value.
2020-02-17 11:22:11 -05:00
2022-11-17 14:12:05 -05:00
When connecting to an Arduino UNO one can use the 3V3 of the Arduino to power the sensor.
However it is not possible to connect the enable pin directly to the sensor.
Use a voltage divider (10K + 20K) to convert the 5 Volts to ~3.3 Volts.
2020-02-17 11:22:11 -05:00
2021-05-28 07:39:01 -04:00
2021-06-20 03:13:49 -04:00
## Interface
2023-02-18 14:42:39 -05:00
```cpp
#include "ML8511.h"
```
#### Constructor
2021-11-09 14:05:19 -05:00
- **ML8511(uint8_t analogPin, uint8_t enablePin = 0xFF)** Constructor,
if enable is connected to 3V3 constantly one does not need to set the enablePin parameter.
2023-02-18 14:42:39 -05:00
#### Core
2021-11-09 14:05:19 -05:00
- **float getUV(uint8_t energyMode = HIGH)** returns mW per cm2, energyMode = HIGH or LOW.
2023-02-18 14:42:39 -05:00
LOW will disable the sensor after each read.
- **float voltage2mW(float voltage)** returns mW per cm2 from voltage.
To be used when one uses an external ADC e.g. ADS1115
2021-11-09 14:05:19 -05:00
- **void setVoltsPerStep(float voltage, uint32_t steps)** to calibrate the **internal** ADC used.
Voltage must be > 0 otherwise it is not set and the default of 5 volts 1023 steps is used.
This function has no meaning for an external ADC.
- **float getVoltsPerStep()** idem.
- **void enable()** manually enable.
- **void disable()** manually disable.
- **bool isEnabled()** get enabled status.
2021-06-20 03:13:49 -04:00
2021-11-09 14:05:19 -05:00
#### Experimental
2021-06-20 03:13:49 -04:00
WARNING: USE WITH CARE
- **float estimateDUVindex(float mWcm2)** input in mW per cm2, returns a value between 0 and ~15(?)
2021-11-09 14:05:19 -05:00
- **void setDUVfactor(float factor)** set the conversion factor
2021-06-20 03:13:49 -04:00
- **float getDUVfactor()** returns the set conversion factor (default 1.61)
2022-11-17 14:12:05 -05:00
See below (Experimental DUVindex) how to determine the DUV factor for your sensor.
2021-06-20 03:13:49 -04:00
2022-11-17 14:12:05 -05:00
_Note:
2021-11-09 14:05:19 -05:00
The UV index can be very high, in La Paz, Bolivia, one of the highest cities in the world
the DUV index can go above 20. See link below.
This is really extreme and it is unknown how the ML8511 sensor (and this library) behaves under such conditions, and how long the sensor would survive.
2022-11-17 14:12:05 -05:00
Datasheet goes up to 15 mW per cm2, with a default DUVfactor of ~1.61 the measurements could handle DUV of ~24 in theory._
2021-11-09 14:05:19 -05:00
https://edition.cnn.com/2021/11/03/americas/bolivia-heatwave-highlands-intl/index.html
2021-06-20 03:13:49 -04:00
2020-02-17 11:22:11 -05:00
## Sensor sensitivity
2021-11-09 14:05:19 -05:00
Indoors there is very little or no UV light so use a known UV source like
2021-06-20 03:13:49 -04:00
a black-light or go outside in the sun.
2020-02-17 11:22:11 -05:00
2020-11-27 05:20:37 -05:00
The formula to convert the ADC reading to mW cm^2 is based upon the graph
2020-02-17 11:22:11 -05:00
shown in the datasheet. As I have no reference source to calibrate the library
2021-11-09 14:05:19 -05:00
the accuracy is limited at best. If you know of a calibrated source please let me know.
2020-11-27 05:20:37 -05:00
The sensor has its peak sensitivity ( >80% ) from λ = 300-380 nm
with an absolute peak at λ = 365 nm.
2021-05-28 07:39:01 -04:00
2021-06-20 03:13:49 -04:00
## Experimental DUVindex
Note: this library is **NOT** calibrated so **USE AT OWN RISK**
The DUV index can be used for warning for sunburn etc.
2021-11-09 14:05:19 -05:00
2021-06-20 03:13:49 -04:00
#### DUV index table
Based upon https://en.wikipedia.org/wiki/Ultraviolet_index,
2023-02-18 14:42:39 -05:00
| DUV INDEX | Description |
|:-----------:|:--------------|
| 0 - 2 | LOW |
| 3 - 5 | MODERATE |
| 6 - 7 | HIGH |
| 8 - 10 | VERY HIGH |
| 11+ | EXTREME |
2021-11-09 14:05:19 -05:00
#### Calibrate estimateDUVindex()
To calibrate the **estimateDUVindex()** function one needs to determine the DUVfactor.
To do this you need an external reference e.g. a local or nearby weather station.
You need to make multiple measurements during the (preferably unclouded) day and
calculate the factor.
```
DUV from weather station
factor = --------------------------
getUV();
```
you do this e.g. once per hour, so you get multiple values.
You can then average them to have a single factor.
Hardcode this found value in the library (in the constructor) or better
use the **setDUVfactor(factor)** call in **setup()** to calibrate your sensor.
2021-06-20 03:13:49 -04:00
2022-11-17 14:12:05 -05:00
## Version info
2021-06-20 03:13:49 -04:00
#### 0.1.5 and before
2020-11-27 05:20:37 -05:00
2021-11-09 14:05:19 -05:00
The formula for the experimental **estimateDUVindex(mWcm2)** is based on
2020-11-27 05:20:37 -05:00
the following facts / assumptions:
2021-01-29 06:31:58 -05:00
- (fact) The sensor cannot differentiate between wavelengths,
2020-11-27 05:20:37 -05:00
so integration with different weights is not possible.
2021-01-29 06:31:58 -05:00
- (assumption) All the UV is radiated at λ = 300 nm.
2020-11-27 05:20:37 -05:00
This is the most lethal the sensor can sense > 80%.
2021-01-29 06:31:58 -05:00
- (choice) All the UV is accounted for 100% for the whole value.
2020-11-27 05:20:37 -05:00
(Erythemal action spectrum)
2021-11-09 14:05:19 -05:00
As we cannot differentiate wavelengths, this is the safest choice.
2020-11-27 05:20:37 -05:00
2021-06-20 03:13:49 -04:00
#### 0.1.6
2020-11-27 05:20:37 -05:00
2021-06-20 03:13:49 -04:00
The formula is simplified to a single factor that the user needs to determine.
Below is described how to do the calibration.
2020-11-27 05:20:37 -05:00
2021-06-20 03:13:49 -04:00
2021-12-21 14:51:35 -05:00
2021-11-09 14:05:19 -05:00
## External ADC
2021-06-20 03:13:49 -04:00
2021-11-09 14:05:19 -05:00
**float voltage2mW(float voltage)** can be used for an external ADC e.g ADS1015,
ADS1115 or one of the (fast) MCP_ADC's.
2021-06-20 03:13:49 -04:00
2022-11-17 14:12:05 -05:00
- https://github.com/RobTillaart/ADS1X15
- https://github.com/RobTillaart/MCP_ADC
2020-11-27 05:20:37 -05:00
## More about UV
https://en.wikipedia.org/wiki/Ultraviolet_index
2020-02-17 11:22:11 -05:00
2021-05-28 07:39:01 -04:00
2021-11-09 14:05:19 -05:00
## Future
2023-02-18 14:42:39 -05:00
#### Must
2022-11-17 14:12:05 -05:00
- improve documentation
2021-11-09 14:05:19 -05:00
- refactor / reorganize readme.md
2022-11-17 14:12:05 -05:00
2023-02-18 14:42:39 -05:00
#### Should
2021-11-09 14:05:19 -05:00
- test more
- get unit tests up and running
- investigate in calibration
- check performance
2022-11-17 14:12:05 -05:00
2023-02-18 14:42:39 -05:00
#### Could
2021-11-09 14:05:19 -05:00
- investigate serial UV communication with UV led
- voltage2mW -> handle negative voltages by taking abs value?
2022-11-17 14:12:05 -05:00
2023-02-18 14:42:39 -05:00
#### Wont
2021-05-28 07:39:01 -04:00