A Si1145 sensor Micropython example on an ESP32

In this example we connect a Si1145 sensor to an ESP32 running Micropython

The Si1145/46/47 is a low-power, reflectance-based, infrared proximity, ultraviolet (UV) index, and ambient light sensor with I2C digital interface and programmableevent interrupt output. This touchless sensor IC includes an analog-to-digital converter, integrated high-sensitivity visible and infrared photodiodes, digital signal processor, and one, two, or three integrated infrared LED drivers with fifteen selectable drive levels.

The Si1145/46/47 offers excellent performance under a wide dynamic range and a variety of light sources including direct sunlight. The Si1145/46/47 can also work under dark glass covers.

The photodiode response and associated digital conversion circuitry provide excellent immunity to artificial light flicker noise and natural light flutter noise. With two or more LEDs, the Si1146/47 is capable of supporting multiple-axis proximity motion detection

 

Parts List

 

Name Link
ESP32 WEMOS WiFi & Bluetooth Battery ESP32 development tool ESP32 battery esp8266 ESP WROOM 32 ESP32
Si1145 SI1145 UV IR Visible Sensor I2C GY1145 Light Breakout Board Module
Connecting cables Free shipping Dupont line 120pcs 20cm male to male + male to female and female to female jumper wire

 

Connection

An easy module to connect to an ESP32, SCL is 22 and SDA is 21 on the Wemos board I used, you can see this is the schematic below

 

Code

You can use any method to upload files to the ESP32, I used uPyCraft

The following is based on a github library – https://github.com/neliogodoi/MicroPython-SI1145. The first part of this is the library which I upload to my ESP32

I used the si1145_lowmem.py library

"""
MicroPython driver for SI1145 light I2C sensor, low memory version :
https://github.com/neliogodoi/MicroPython-SI1145
Version: 0.3.0 @ 2018/04/02
"""
 
import time
from ustruct import unpack
 
class SI1145(object):
 
    def __init__(self, i2c=None, addr=0x60):
        if i2c is None:
            raise ValueError('An I2C object is required.')
        self._i2c = i2c
        self._addr = addr
        self._reset()
        self._load_calibration()
 
    def _read8(self, register):
        result = unpack(
            'B',
            self._i2c.readfrom_mem(
                self._addr, register, 1)
        )[0] & 0xFF
        return result
 
    def _read16(self, register, little_endian=True):
        result = unpack('BB', self._i2c.readfrom_mem(self._addr, register, 2))
        result = ((result[1] << 8) | (result[0] & 0xFF))
        if not little_endian:
            result = ((result << 8) & 0xFF00) + (result >> 8)
        return result
 
    def _write8(self, register, value):
        value = value & 0xFF
        self._i2c.writeto_mem(self._addr, register, bytes([value]))
 
    def _reset(self):
        self._write8(0x08, 0x00)
        self._write8(0x09, 0x00)
        self._write8(0x04, 0x00)
        self._write8(0x05, 0x00)
        self._write8(0x06, 0x00)
        self._write8(0x03, 0x00)
        self._write8(0x21, 0xFF)
        self._write8(0x18, 0x01)
        time.sleep(.01)
        self._write8(0x07, 0x17)
        time.sleep(.01)
 
    def _write_param(self, parameter, value):
        self._write8(0x17, value)
        self._write8(0x18, parameter | 0xA0)
        return self._read8(0x2E)
 
    def _load_calibration(self):
        self._write8(0x13, 0x7B)
        self._write8(0x14, 0x6B)
        self._write8(0x15, 0x01)
        self._write8(0x16, 0x00)
        self._write_param( 0x01, 0x80 | 0x40 | 0x20 | 0x10 | 0x01)
        self._write8(0x03, 0x01)
        self._write8(0x04, 0x01)
        self._i2c.writeto_mem(0x60, 0x0F, b'0x03')
        self._write_param(0x07, 0x03)
        self._write_param(0x02, 0x01)
        self._write_param(0x0B, 0)
        self._write_param(0x0A, 0x70)
        self._write_param(0x0C, 0x20 | 0x04)
        self._write_param(0x0E, 0x00)
        self._write_param(0x1E, 0)
        self._write_param(0x1D, 0x70)
        self._write_param(0x1F, 0x20)
        self._write_param(0x11, 0)
        self._write_param(0x10, 0x70)
        self._write_param(0x12, 0x20)
        self._write8(0x08, 0xFF)
        self._write8(0x18, 0x0F)
 
    @property
    def read_uv(self):
        return self._read16(0x2C, little_endian=True) / 100
 
    @property
    def read_visible(self):
        return self._read16(0x22, little_endian=True)
 
    @property
    def read_ir(self):
        return self._read16(0x24, little_endian=True)
 
    @property
    def read_prox(self):
        return self._read16(0x26, little_endian=True)

I then create a file called main.py and uploaded them to my ESP32

import machine
import si1145
import time
 
i2c = machine.I2C(sda=machine.Pin(21),scl=machine.Pin(22))
sensor = si1145.SI1145(i2c=i2c)
 
for i in range(10):
    uv = sensor.read_uv
    ir = sensor.read_ir
    view = sensor.read_visible
    print(" UV: %f\n IR: %f\n Visible: %f" % (uv, ir, view))
    time.sleep(1)

Testing

Open up the REPL window. Here is what I saw in uPyCraft

Ready to download this file,please wait!

download ok
exec(open(‘./main.py’).read(),globals())
UV: 0.000000
IR: 407.999992
Visible: 265.999984
UV: 0.040000
IR: 407.999992
Visible: 265.999984
UV: 0.040000
IR: 417.999982
Visible: 265.999984
UV: 0.040000
IR: 411.999988
Visible: 266.999983
UV: 0.040000
IR: 409.999990
Visible: 266.999983

Links

https://www.silabs.com/documents/public/data-sheets/Si1145-46-47.pdf

LEAVE A REPLY

Please enter your comment!
Please enter your name here