/ adafruit_veml6075.py
adafruit_veml6075.py
1 # The MIT License (MIT) 2 # 3 # Copyright (c) 2018 ladyada for Adafruit Industries 4 # 5 # Permission is hereby granted, free of charge, to any person obtaining a copy 6 # of this software and associated documentation files (the "Software"), to deal 7 # in the Software without restriction, including without limitation the rights 8 # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 # copies of the Software, and to permit persons to whom the Software is 10 # furnished to do so, subject to the following conditions: 11 # 12 # The above copyright notice and this permission notice shall be included in 13 # all copies or substantial portions of the Software. 14 # 15 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 # THE SOFTWARE. 22 """ 23 `adafruit_veml6075` 24 ==================================================== 25 26 CircuitPython library to support VEML6075 UVA & UVB sensor. 27 28 * Author(s): ladyada 29 30 Implementation Notes 31 -------------------- 32 33 **Hardware:** 34 35 **Software and Dependencies:** 36 37 * Adafruit CircuitPython firmware for the supported boards: 38 https://github.com/adafruit/circuitpython/releases 39 40 * Adafruit's Bus Device library: https://github.com/adafruit/Adafruit_CircuitPython_BusDevice 41 42 """ 43 44 __version__ = "0.0.0-auto.0" 45 __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_VEML6075.git" 46 47 # imports 48 49 import time 50 from adafruit_bus_device.i2c_device import I2CDevice 51 from micropython import const 52 53 # pylint: disable=bad-whitespace 54 _VEML6075_ADDR = const(0x10) 55 56 _REG_CONF = const(0x00) 57 _REG_UVA = const(0x07) 58 _REG_DARK = const(0x08) # check is true? 59 _REG_UVB = const(0x09) 60 _REG_UVCOMP1 = const(0x0A) 61 _REG_UVCOMP2 = const(0x0B) 62 _REV_ID = const(0x0C) 63 64 # Valid constants for UV Integration Time 65 _VEML6075_UV_IT = {50: 0x00, 100: 0x01, 200: 0x02, 400: 0x03, 800: 0x04} 66 # pylint: enable=bad-whitespace 67 68 69 class VEML6075: 70 """ 71 Driver base for the VEML6075 UV Light Sensor 72 :param i2c_bus: The `busio.I2C` object to use. This is the only required parameter. 73 :param int integration_time: The integration time you'd like to set initially. Availble 74 options - each in milliseconds: 50, 100, 200, 400, 800. 75 The higher the '_x_' value, the more accurate 76 the reading is (at the cost of less samples per reading). 77 Defaults to 100ms if parameter not passed. To change 78 setting after intialization, use 79 ``[veml6075].integration_time = new_it_value``. 80 :param bool high_dynamic: whether to put sensor in 'high dynamic setting' mode 81 :param float uva_a_coef: the UVA visible coefficient 82 :param float uva_b_coef: the UVA IR coefficient 83 :param float uvb_c_coef: the UVB visible coefficient 84 :param float uvb_d_coef: the UVB IR coefficient 85 :param float uva_response: the UVA responsivity 86 :param float uvb_response: the UVA responsivity 87 """ 88 89 def __init__( 90 self, 91 i2c_bus, 92 *, 93 integration_time=50, 94 high_dynamic=True, 95 uva_a_coef=2.22, 96 uva_b_coef=1.33, 97 uvb_c_coef=2.95, 98 uvb_d_coef=1.74, 99 uva_response=0.001461, 100 uvb_response=0.002591 101 ): 102 # Set coefficients 103 self._a = uva_a_coef 104 self._b = uva_b_coef 105 self._c = uvb_c_coef 106 self._d = uvb_d_coef 107 self._uvaresp = uva_response 108 self._uvbresp = uvb_response 109 self._uvacalc = self._uvbcalc = None 110 111 # Init I2C 112 self._i2c = I2CDevice(i2c_bus, _VEML6075_ADDR) 113 self._buffer = bytearray(3) 114 115 # read ID! 116 veml_id = self._read_register(_REV_ID) 117 if veml_id != 0x26: 118 raise RuntimeError("Incorrect VEML6075 ID 0x%02X" % veml_id) 119 120 # shut down 121 self._write_register(_REG_CONF, 0x01) 122 123 # Set integration time 124 self.integration_time = integration_time 125 126 # enable 127 conf = self._read_register(_REG_CONF) 128 if high_dynamic: 129 conf |= 0x08 130 conf &= ~0x01 # Power on 131 self._write_register(_REG_CONF, conf) 132 133 def _take_reading(self): 134 """Perform a full reading and calculation of all UV calibrated values""" 135 time.sleep(0.1) 136 uva = self._read_register(_REG_UVA) 137 uvb = self._read_register(_REG_UVB) 138 # dark = self._read_register(_REG_DARK) 139 uvcomp1 = self._read_register(_REG_UVCOMP1) 140 uvcomp2 = self._read_register(_REG_UVCOMP2) 141 # Equasion 1 & 2 in App note, without 'golden sample' calibration 142 self._uvacalc = uva - (self._a * uvcomp1) - (self._b * uvcomp2) 143 self._uvbcalc = uvb - (self._c * uvcomp1) - (self._d * uvcomp2) 144 # print("UVA = %d, UVB = %d, UVcomp1 = %d, UVcomp2 = %d, Dark = %d" % 145 # (uva, uvb, uvcomp1, uvcomp2, dark)) 146 147 @property 148 def uva(self): 149 """The calibrated UVA reading, in 'counts' over the sample period""" 150 self._take_reading() 151 return self._uvacalc 152 153 @property 154 def uvb(self): 155 """The calibrated UVB reading, in 'counts' over the sample period""" 156 self._take_reading() 157 return self._uvbcalc 158 159 @property 160 def uv_index(self): 161 """The calculated UV Index""" 162 self._take_reading() 163 return ((self._uvacalc * self._uvaresp) + (self._uvbcalc * self._uvbresp)) / 2 164 165 @property 166 def integration_time(self): 167 """The amount of time the VEML is sampling data for, in millis. 168 Valid times are 50, 100, 200, 400 or 800ms""" 169 key = (self._read_register(_REG_CONF) >> 4) & 0x7 170 for k, val in enumerate(_VEML6075_UV_IT): 171 if key == k: 172 return val 173 raise RuntimeError("Invalid integration time") 174 175 @integration_time.setter 176 def integration_time(self, val): 177 if not val in _VEML6075_UV_IT.keys(): 178 raise RuntimeError("Invalid integration time") 179 conf = self._read_register(_REG_CONF) 180 conf &= ~0b01110000 # mask off bits 4:6 181 conf |= _VEML6075_UV_IT[val] << 4 182 self._write_register(_REG_CONF, conf) 183 184 def _read_register(self, register): 185 """Read a 16-bit value from the `register` location""" 186 self._buffer[0] = register 187 with self._i2c as i2c: 188 i2c.write_then_readinto(self._buffer, self._buffer, out_end=1, in_end=2) 189 return (self._buffer[1] << 8) | self._buffer[0] 190 191 def _write_register(self, register, value): 192 """Write a 16-bit value to the `register` location""" 193 self._buffer[0] = register 194 self._buffer[1] = value 195 self._buffer[2] = value >> 8 196 with self._i2c as i2c: 197 i2c.write(self._buffer)