Sunday, 12 March 2017 12:44

TSL2561 Luminosity Sensor - IR and Visible Light

Written by 
  • Author Type: School, Other Educational and Groups
  • Country: UK

The TSL2561 Luminosity Sensor is used to measure ambiant light levels more accuratly and across a wider range of light levels than a Light Dependant Resistor or LDR.

The TSL2561 has two light sensors, one photo diode detects a range from infrared through full spectrum visible light. The other photo diode just detect infrared light. The visible light levels are then calculated by taking the IR reading away from the reading of the IR+visible reading. From this the Lux can be calculated. The sensors can detect a LUX of 0.1 to 40,000. To put that in perspective from a partially moon lit night to brighter than daylight on sunny day, not looking at the sun. Lux examples on Wikipedia

This type of sensor is used to get light readings for photography and video, used in electronics to manage light levels such as the brightness of a display and also useful for security devices.


The pins are not supplied with the board

The TSL2561 measures only 15mm x 18mm and has 5 connectors but only 4 are required to use it. It is powered by 3.3V and uses the i2c connectors on the Raspberry Pi's GPIO ports. The 5th connector can be used as an interupt when certain light levels are detected. The board is supplied with no pins.

 There are 3 i2c addresses that can be used to access the TSL2561 light sensor, the default one is 039 the others of 029 and 049 are set by solder jumpers or pins depending on the manufacturer of the board.

The controls of the TSL2561 allow you to:

  • turn it on and off
  • set the Gain levels, light sensitivity, between normal x1 and low light x16
  • Exposure time between 0.402ms , 101ms, 13.7ms or manual exposure length
  • Interupt thresholds for use with the 5th pin, INT.
  • Display Part Number
  • Retreive results from the two photo diode channels.

 To program the sensor there are a few drivers around for C and Python. For this article I will cover what is required to program in Python3.

First of all make sure you have the 12c libraries installed on your Raspberry Pi.

dpkg -s python3-smbusdpkg -s i2c-tools

If it is not installed then install it with

sudo apt-get install python3-smbussudo apt-get install i2c-tools

The I2C interface will also need activating on the Raspberry Pi. This is done either in the Raspbian desktop in preferences and Raspberry Configuration. Go to the Interfaces tab and enable I2C.

To do this in the terminal enter

sudo raspi-config

Go to the Interfacing Options, then P5 I2C, then select yes.

Ok your way out and select reboot.

You are now set to start programming the Light Sensor.

to confirm the TSL2561's i2c address is 039 run the command

i2cdetect -y 1

You should see a table with lots of dashes and a number. The number will be the address of the I2C device attached. This should be 39.

 To setup the Luminosity sensor you need to write to the sensors memory with the settings you want. This consists of the (i2c address, Function address, Command, setting).

For example, to switch it on the command is

bus.write_byte_data(0x39, 0x00 | 0x80, 0x03)

(I2C address, function address | Command, setting)

 if you want to change the gain to x16 then you would use

 bus.write_byte_data(0x39, 0x01 | 0x80, 0x12)

I will explain the options in more detail to make this a bit clearer.

The I2C address (0x39) and comand (0x80) don't change, you will only change the other two options. The second position is the function you wish to use.

  •  0x00 = used to switch on and off
  • 0x01 = Timing, used to set exposure speed or manual mode
  • 0x02 - 0x05 = Set the low and high threshold for the Interupt
  • 0x06 = Set Interrupt
  • 0x0A = Part number / ID
  • 0x0C = Channel 0 Photo Diode 1 results
  • 0x0D = second part of Photo Diode 1 results but can only be accessed through  a block read of 0x0C
  • 0x0E = Channel 1 Photo Diaode 2 results
  • 0x0F = second part of Photo Diode 2 results but can only be accessed through  a block read of 0x0E

List of TSL2561 Command Options

This list shows the entries between the brackets of  bus.write_byte_data(0x39, 0x00 | 0x80, 0x03) which activate each setting. The entries are in hexidecimal but can be entered in decimal. ie bus.write_byte_data(57, 0 | 128, 3). To be consistant with the datasheet I will use Hexidecimal.

  • (0x39, 0x00 | 0x80, 0x03 ) = Switch on
  • (0x39, 0x00 | 0x80, 0x00) = Switch off
  • (0x39, 0x01 | 0x80, 0x00) = Gain at 1x and exposure at 13.7ms
  • (0x39, 0x01 | 0x80, 0x01) = Gain at 1x and exposure at 100ms
  • (0x39, 0x01 | 0x80, 0x02) = Gain at 1x and exposure at 402ms
  • (0x39, 0x01 | 0x80, 0x03) = Gain x1 and Manual exposure
  • (0x39, 0x01 | 0x80, 0x10) = Gain x16 low light and exposure at 13.7ms
  • (0x39, 0x01 | 0x80, 0x11) = Gain x16 low light and exposure at 100ms
  • (0x39, 0x01 | 0x80, 0x12) = Gain x16 low light and exposure at 402ms
  • (0x39, 0x01 | 0x80, 0x13) = Gain x16 low light and Manual exposure
  • (0x39, 0x01 | 0x80, 0x1F) = Start Manual Exposure
  • (0x39, 0x01 | 0x80, 0x1E) = Stop Manual Exposure

I haven't used the interrupts with the 5th pin so have not included the commands for this. They are documented in the datasheet at the bottom of this article.

Next are the read commands:

To read the part number and ID enter the command is bus.read_byte_data(0x39, 0x8A)

To read the two sets of numbers in the IR_Visible sensor for channel 0 use

bus.read_i2c_block_data(0x39, 0x0C | 0x80, 2)

and for the two sets of data for the IR sensor for channel 1 use

bus.read_i2c_block_data(0x39, 0x0E | 0x80, 2)

Convert the photo diodes output

The sensors return results from the two channels like [210,16] and [74,1]. These should be converted to a integer before being used with the following calculation, where [210,16) is data0 and [74,1] is data1

channel0 = data0[1] * 256 + data0[0]

channel1 = data1[1] * 256 + data1[0]

This gives you the sensors readings. To get the visible light result minus channel1 (IR) from channel0 (IR+Visible).

The visible light result can then be used to calculate the lux level. This involves various calculations based on the gain and exposure time. Lux calculation examples are shown in the datasheet at the bottom of this article.


 Some Example TSL2561 Light Readings

Some readings taken in a halogen lit room.

  • 1x Gain at 402ms: V+IR 484  IR 301
  • 16x Gain at 402ms: V+IR 7222  IR 4510

 Enclosed in hands

  • 1x Gain at 402ms: V+IR 1  IR 1
  • 16x Gain at 402ms: V+IR 26  IR 18

IR Remote control pointed at sensor

  • 1x Gain at 402ms: V+IR 1637  IR 1427
  • 16x Gain at 402ms: V+IR 40567  IR 39371


Depending on the exposure there is a maximum readings the sensor will return.

For 402ms the readings will go up to 65535, 101ms the maximum is 37177 and 13.7ms it is 5047. Any light exceding these levels will not be recorded. If these levels are met then the reading should be treated as bad.


Python 3 Script to test the TSL2561 Luminosity Sensor

I have written a python 3 script to test the sensor in different condition. There are a few scripts and libraries found elsewhere online but have written this to get a better understanding of the features for future projects.

It can be downloaded from here


#Output test for TSL2561 Luminosity Sensor
import smbus
import time
TSLaddr = 0x39 #Default I2C address, alternate 0x29, 0x49 
TSLcmd = 0x80 #Command
chan0 = 0x0C #Read Channel0 sensor date
chan1 = 0x0E #Read channel1 sensor data
TSLon = 0x03 #Switch sensors on
TSLoff = 0x00 #Switch sensors off
#Exposure settings
LowShort = 0x00 #x1 Gain 13.7 miliseconds
LowMed = 0x01 #x1 Gain 101 miliseconds
LowLong = 0x02 #x1 Gain 402 miliseconds
LowManual = 0x03 #x1 Gain Manual
HighShort = 0x10 #LowLight x16 Gain 13.7 miliseconds
HighMed = 0x11	#LowLight x16 Gain 100 miliseconds
HighLong = 0x12 #LowLight x16 Gain 402 miliseconds
HighManual = 0x13 #LowLight x16 Gain Manual
#Manual Settings
ManDelay = 2 #Manual Exposure in Seconds
StartMan = 0x1F #Start Manual Exposure
EndMan = 0x1E #End Manual Exposure
#Number of sensor readings
vRepeat = 20
	#Enter in [] the Exposure Setting to use 
	sequence = [HighLong]*vRepeat #repeat reading vRepeat times for setting in []
	print("Unknown Exposure Setting used, defaulting to LowLong (x1 402ms")
	sequence = [LowLong]*vRepeat
# Get I2C bus
bus = smbus.SMBus(1)
writebyte = bus.write_byte_data
#Power On
writebyte(TSLaddr, 0x00 | TSLcmd, TSLon)
def luxcalc(Result0, Result1):
	"""Basic Lux Calculation value"""
	#see data sheet for lux calculation details
	#and to calculate lux correctly for all modes
	ResDiv = int(Result1)/int(Result0)
	if ResDiv  0.52 and ResDiv  0.65 and ResDiv  0.8 and ResDiv  1.3:
		lux = 0
	return lux
def manual(delay,mode):
	"""manual exposure"""
	bus.write_byte_data(TSLaddr, 0x01 | TSLcmd, mode) #sensativity mode
	bus.write_byte_data(TSLaddr, 0x01 | TSLcmd, StartMan) #start detection
	time.sleep(delay) #exposure
	bus.write_byte_data(TSLaddr, 0x01 | TSLcmd, EndMan) #stop detection
def CurTime():
	"""Returns the current date and time"""
	t1 = time.asctime(time.localtime(time.time()))	
	return t1
print("Part Number", bus.read_byte_data(TSLaddr, 0x8A))
for item in sequence:
	if item != 3 and item != 19: #Selected built in delay for exposure. If Manual  mode not set (0x03 or 0x13)
		writebyte(TSLaddr, 0x01 | TSLcmd, item)
		#Give sensor time to write results before collecting reading. 
		#13.7ms  write several readings before sleep complete, 402ms would write once at 0.5sec sleep.
	else: #use manual exposure
	#Read Ch0 Word
	data = bus.read_i2c_block_data(TSLaddr, chan0 | TSLcmd, 2)
	#Read CH1 Word
	data1 = bus.read_i2c_block_data(TSLaddr, chan1 | TSLcmd, 2)
	# Convert the data to Integer
	ch0 = data[1] * 256 + data[0]
	ch1 = data1[1] * 256 + data1[0]
	# Output data to screen
	vTime = CurTime()
	if ch0 > 0:
		vLux = round(luxcalc(ch0, ch1),5)
		print(vTime," V+IR",ch0, " IR",ch1, "Lux",vLux)
		#either no light or clipping value exceeded due to too much light
		print(vTime, " V+IR",ch0, " IR",ch1, "No Light")
#Power Off
writebyte(TSLaddr, 0x00 | TSLcmd, TSLoff)

The script will give 20 readings for the exposure setting used.

To change the exposure use a varible from the "#Exposure Settings" and put it in the line

sequence = [HighLong]*vRepeat #repeat reading vRepeat times for setting in []

options are LowShort, LowMed, LowLong, LowManual, HighShort, HighMed, HighLong, HighManual

changing; vRepeat = 20, will change the amount of readings recorded from 20.

For the LowManual and HighManual exposure settings change the exposure length, in seconds, with;

ManDelay = 2 #Manual Exposure in Seconds



Other scripts can be found at:

 The TAOS TSL2560 and TSL2561 Light to Digital Converter datasheet is available here






Last modified on Friday, 24 March 2017 21:32
roboberry SuperUser.  Contactable via the site admin e-mail in the Contact Us link.


Leave a comment

Comments for Guest and account owners. Account owners will need to login to use registered e-mail address.

Additional information