That should work. But you should also refer to the adafruit library as a sanity checkpandring wrote:Now, I just need to get the values into a usable format (i.e. lux). Correct me if I'm wrong, but I assume I should just use the algorithm found on page 22 of the data sheet.
TSL2561 and Raspberry Pi
Moderators: adafruit_support_bill, adafruit
Please be positive and constructive with your questions and comments.
- adafruit_support_rick
- Posts: 35092
- Joined: Tue Mar 15, 2011 11:42 am
Re: TSL2561 and Raspberry Pi
-
- Posts: 25
- Joined: Sun Dec 02, 2012 5:15 pm
Re: TSL2561 and Raspberry Pi
Here's my code:
Code: Select all
from Adafruit_I2C import Adafruit_I2C
address = 0x39
i2c = Adafruit_I2C(address)
control_on = 0x03
control_off = 0x00
def enable():
print "enabling"
i2c.write8(0x80, control_on)
def disable():
print "disabling"
i2c.write8(0x80, control_off)
def getLight():
x = i2c.readU16(0xAE);
x <<= 16;
x |= i2c.readU16(0xAC);
return x
enable()
print "Light:"
print getLight()
-
- Posts: 25
- Joined: Sun Dec 02, 2012 5:15 pm
Re: TSL2561 and Raspberry Pi
@Driverblock:
So is the TSL2561 sold by adafruit the "T" or the "CS" version? I'm not sure if I have the TMB or chipscale version.
Also, you said I should combine both 16 bit values into a 32 bit value, but it looks like you need the separate values to be able to calculate lux. How do I get the channel 0 and channel 1 values if I need to combine them into one 32 bit string?
So is the TSL2561 sold by adafruit the "T" or the "CS" version? I'm not sure if I have the TMB or chipscale version.
Also, you said I should combine both 16 bit values into a 32 bit value, but it looks like you need the separate values to be able to calculate lux. How do I get the channel 0 and channel 1 values if I need to combine them into one 32 bit string?
- static
- Posts: 188
- Joined: Thu Dec 23, 2010 6:21 pm
Re: TSL2561 and Raspberry Pi
Looking at the first page, I think we're looking at the T-Package.
I'm playing around with your code, but I'm really confused by the getLight() function. As far as I know, a semi-colon is used to put several lines of code on a single line. Are they necessary here?
I rewrote the code a little bit so that each value stored before being re-checked or altered by the code.
I'm looking at page 17 and 18 on the datasheet. It mentions bit-shifting and shadow registers. Does this mean that it matters which register we read first? Should we be looking at 0xAC first and then OxAE? Experimenting with the code and subsequent data readouts, I am getting significantly different values when I switch which order I'm pulling the data.
I'm playing around with your code, but I'm really confused by the getLight() function. As far as I know, a semi-colon is used to put several lines of code on a single line. Are they necessary here?
I rewrote the code a little bit so that each value stored before being re-checked or altered by the code.
Code: Select all
def getLight():
x = i2c.readU16(0xAE)
w = x
x <<= 16
y=x
x|=i2c.readU16(0xAC)
return w,x,y
- adafruit_support_rick
- Posts: 35092
- Joined: Tue Mar 15, 2011 11:42 am
Re: TSL2561 and Raspberry Pi
The T versionpandring wrote:So is the TSL2561 sold by adafruit the "T" or the "CS" version?
I didn't say you had to do that. I was just illustrating what the arduino library function did. To get the individual values, just assign the read16 results from channel 0 and channel 1 to different variables.pandring wrote:Also, you said I should combine both 16 bit values into a 32 bit value, but it looks like you need the separate values to be able to calculate lux. How do I get the channel 0 and channel 1 values if I need to combine them into one 32 bit string?
- static
- Posts: 188
- Joined: Thu Dec 23, 2010 6:21 pm
Re: TSL2561 and Raspberry Pi
Why do we need the bit shift, if we're pulling the values separately?
Code: Select all
def getLight2():
x = i2c.readU16(0xAC)
y = i2c.readU16(0xAE)
return x,y
- adafruit_support_rick
- Posts: 35092
- Joined: Tue Mar 15, 2011 11:42 am
Re: TSL2561 and Raspberry Pi
You don't. My approach to this problem would be to simply port the Adafruit arduino library. The C++ code will map pretty easily into python code. I used the getFullLuminosity() function as an example. It reads both registers and packs them into a uint32_t for the return value. The caller then unpacks that back into individual 16-bit values.
C++ doesn't allow two return values, hence the uint32_t. If you can return two int16's from a python function, then there's no need for the shift.
While building this library by referring only the datasheet may be an interesting exercise, you will cut your BANNED expenses significantly by simply porting the C++. It doesn't amount to much more than juggling a few keywords and punctuation symbols.
I'm also see a lot of literals like readU16(0xAE). Very bad. You want to use constants the way the arduino library does. In my example, I reduced the constants down to literals as an illustration.
C++ doesn't allow two return values, hence the uint32_t. If you can return two int16's from a python function, then there's no need for the shift.
While building this library by referring only the datasheet may be an interesting exercise, you will cut your BANNED expenses significantly by simply porting the C++. It doesn't amount to much more than juggling a few keywords and punctuation symbols.
I'm also see a lot of literals like readU16(0xAE). Very bad. You want to use constants the way the arduino library does. In my example, I reduced the constants down to literals as an illustration.
- static
- Posts: 188
- Joined: Thu Dec 23, 2010 6:21 pm
Re: TSL2561 and Raspberry Pi
Code: Select all
from Adafruit_I2C import Adafruit_I2C
import time
import math
address = 0x39
i2c = Adafruit_I2C(address)
control_on = 0x03
control_off = 0x00
def enable():
print("enabling")
i2c.write8(0x80, control_on)
def disable():
print("disabling")
i2c.write8(0x80, control_off)
def getLight():
ch0 = i2c.readU16(0xAC) ##Broad spectrum photo-diode
ch1 = i2c.readU16(0xAE) ##IR spectrum photo-diode
return ch0,ch1
def getLux():
ch0,ch1 = getLight()
ratio = 0
lux = 0
tag = 0
if ch0 > 0:
ratio = float(ch1)/float(ch0)
if ch0 == 0:
ratio = 1.35
if ratio > 1.30:
lux = 0
tag = 0
elif ratio > 0.80:
lux = (0.00146 * ch0) - (0.00112 * ch1)
tag = 4
elif ratio > 0.61:
lux = (0.0128 * ch0) - (0.0153 * ch1)
tag =3
elif ratio > 0.50:
lux = (0.0224 * ch0) - (0.031 * ch1)
tag = 2
elif ratio <= 0.50:
lux = (0.0304 * ch0) - (0.062 * ch0 * ((ch1/ch0) ** 1.4))
tag =1
return lux, ratio, tag, ch0, ch1
enable()
#time.sleep(0.4)
light = getLight()
lux = getLux()
print(light)
print(lux)
#disable()
I need to clean the code up, and implement DriverBlock's suggestion of implementing constants. I'm pretty sure the if/elif loop describes the function in the datasheet.
I wrote this in Python 3. I think the only thing that needs to be changed for Python 2.x functionality is to switch the print() statements to Python 2.x print statements.
- static
- Posts: 188
- Joined: Thu Dec 23, 2010 6:21 pm
Re: TSL2561 and Raspberry Pi
Python 3 code:
Hopefully, Python 2.x code:
I still don't understand the bizarre behavior when I put a ton of light on the sensor. I tried a couple of different methods to see what was happening with the lux mathematical function, but I couldn't really piece it together (lack of sleep?).
Code: Select all
from Adafruit_I2C import Adafruit_I2C
import time
import math
address = 0x39
i2c = Adafruit_I2C(address)
control_on = 0x03
control_off = 0x00
BSPD = 0xAC #### Broad Spectrum Photo-Diode (Visible and IR)
IRPD = 0xAE #### IR spectrum Photo-Diode
def enable():
print("enabling")
i2c.write8(0x80, control_on)
def disable():
print("disabling")
i2c.write8(0x80, control_off)
def getLight():
ch0 = i2c.readU16(BSPD) ##Broad spectrum photo-diode
ch1 = i2c.readU16(IRPD) ##IR spectrum photo-diode
return ch0,ch1
def getLux():
"""This code appears to give wonky results at times (wonky being a highly
technical term). When the light sensing apparatus is struck by a relatively
intense light, the results are unpredictable"""
ch0,ch1 = getLight()
ratio = 0
lux = 0
tag = 0
if ch0 > 0:
ratio = float(ch1)/float(ch0)
#if ch0 == 0:
#ratio = 1.35
if ratio > 1.30:
lux = 0
tag = 0
elif ratio > 0.80:
lux = (0.00146 * ch0) - (0.00112 * ch1)
tag = 4
elif ratio > 0.61:
lux = (0.0128 * ch0) - (0.0153 * ch1)
tag =3
elif ratio > 0.50:
lux = (0.0224 * ch0) - (0.031 * ch1)
tag = 2
elif ratio <= 0.50:
lux = (0.0304 * ch0) - (0.062 * ch0 * ((ch1/ch0) ** 1.4))
tag =1
return lux
def getLuxData():
ch0,ch1 = getLight()
ratio = 0
lux = 0
tag = 0
if ch0 > 0:
ratio = float(ch1)/float(ch0)
#if ch0 == 0:
#ratio = 1.35
if ratio > 1.30:
lux = 0
tag = 0
elif ratio > 0.80:
lux = (0.00146 * ch0) - (0.00112 * ch1)
tag = 4
elif ratio > 0.61:
lux = (0.0128 * ch0) - (0.0153 * ch1)
tag =3
elif ratio > 0.50:
lux = (0.0224 * ch0) - (0.031 * ch1)
tag = 2
elif ratio <= 0.50:
lux = (0.0304 * ch0) - (0.062 * ch0 * ((ch1/ch0) ** 1.4))
tag =1
return lux, tag, ratio, ch0, ch1
enable()
lux = getLux()
print(lux)
#while 1 > 0:
# lux, tag, ratio, ch0, ch1 = getLuxData()
# if lux > 10:
# lux = int(lux)
# ratio = round(ratio, 4)
# print(lux, ratio)
# time.sleep(0.5)
Code: Select all
from Adafruit_I2C import Adafruit_I2C
import time
import math
address = 0x39
i2c = Adafruit_I2C(address)
control_on = 0x03
control_off = 0x00
BSPD = 0xAC #### Broad Spectrum Photo-Diode (Visible and IR)
IRPD = 0xAE #### IR spectrum Photo-Diode
def enable():
print"enabling"
i2c.write8(0x80, control_on)
def disable():
print"disabling"
i2c.write8(0x80, control_off)
def getLight():
ch0 = i2c.readU16(BSPD) ##Broad spectrum photo-diode
ch1 = i2c.readU16(IRPD) ##IR spectrum photo-diode
return ch0,ch1
def getLux():
"""This code appears to give wonky results at times (wonky being a highly
technical term). When the light sensing apparatus is struck by a relatively
intense light, the results are unpredictable"""
ch0,ch1 = getLight()
ratio = 0
lux = 0
tag = 0
if ch0 > 0:
ratio = float(ch1)/float(ch0)
#if ch0 == 0:
#ratio = 1.35
if ratio > 1.30:
lux = 0
tag = 0
elif ratio > 0.80:
lux = (0.00146 * ch0) - (0.00112 * ch1)
tag = 4
elif ratio > 0.61:
lux = (0.0128 * ch0) - (0.0153 * ch1)
tag =3
elif ratio > 0.50:
lux = (0.0224 * ch0) - (0.031 * ch1)
tag = 2
elif ratio <= 0.50:
lux = (0.0304 * ch0) - (0.062 * ch0 * ((ch1/ch0) ** 1.4))
tag =1
return lux
def getLuxData():
ch0,ch1 = getLight()
ratio = 0
lux = 0
tag = 0
if ch0 > 0:
ratio = float(ch1)/float(ch0)
#if ch0 == 0:
#ratio = 1.35
if ratio > 1.30:
lux = 0
tag = 0
elif ratio > 0.80:
lux = (0.00146 * ch0) - (0.00112 * ch1)
tag = 4
elif ratio > 0.61:
lux = (0.0128 * ch0) - (0.0153 * ch1)
tag =3
elif ratio > 0.50:
lux = (0.0224 * ch0) - (0.031 * ch1)
tag = 2
elif ratio <= 0.50:
lux = (0.0304 * ch0) - (0.062 * ch0 * ((ch1/ch0) ** 1.4))
tag =1
return lux, tag, ratio, ch0, ch1
enable()
lux = getLux()
print lux
#while 1 > 0:
# lux, tag, ratio, ch0, ch1 = getLuxData()
# if lux > 10:
# lux = int(lux)
# ratio = round(ratio, 4)
# print lux, ratio
# time.sleep(0.5)
- adafruit_support_rick
- Posts: 35092
- Joined: Tue Mar 15, 2011 11:42 am
Re: TSL2561 and Raspberry Pi
See bryand's thread:
http://forums.adafruit.com/viewtopic.ph ... 33#p179633
http://forums.adafruit.com/viewtopic.ph ... 33#p179633
- static
- Posts: 188
- Joined: Thu Dec 23, 2010 6:21 pm
Re: TSL2561 and Raspberry Pi
All over it. Time to do some testing.
Thanks man, it really didn't occur to me to search the topic list again.
Thanks man, it really didn't occur to me to search the topic list again.
- static
- Posts: 188
- Joined: Thu Dec 23, 2010 6:21 pm
Re: TSL2561 and Raspberry Pi
Code: Select all
#!/usr/bin/python
import sys
import smbus
import time
from Adafruit_I2C import Adafruit_I2C
### Written for Python 3
### Big thanks to bryand, who wrote the code that I borrowed heavily from/was inspired by
### More thanks pandring who kind of kickstarted my work on the TSL2561 sensor
### A great big huge thanks to driverblock and the Adafruit team (Congrats on your many succeses
### Ladyada). Without you folks I would just be a guy sitting somewhere thinking about cool stuff
### Now I'm a guy building cool stuff.
### If any of this code proves useful, drop me a line at medicforlife.blogspot.com
class Luxmeter:
i2c = None
def __init__(self, address=0x39, debug=0, pause=0.41):
self.i2c = Adafruit_I2C(address)
self.address = address
self.pause = pause
self.debug = debug
self.i2c.write8(0x80, 0x03) # enable the device
self.i2c.write8(0x81, 0x11) # set gain = 16X and timing = 101 mSec
time.sleep(self.pause) # pause for a warm-up
def readfull(self, reg=0x8C):
"""Reads visible + IR diode from the I2C device"""
try:
fullval = self.i2c.readU16(reg)
newval = self.i2c.reverseByteOrder(fullval)
if (self.debug):
print("I2C: Device 0x%02X returned 0x%04X from reg 0x%02X" % (self.address, fullval & 0xFFFF, reg))
return newval
except IOError:
print("Error accessing 0x%02X: Check your I2C address" % self.address)
return -1
def readIR(self, reg=0x8E):
"""Reads IR only diode from the I2C device"""
try:
IRval = self.i2c.readU16(reg)
newIR = self.i2c.reverseByteOrder(IRval)
if (self.debug):
print("I2C: Device 0x%02X returned 0x%04X from reg 0x%02X" % (self.address, IRval & 0xFFFF, reg))
return newIR
except IOError:
print("Error accessing 0x%02X: Check your I2C address" % self.address)
return -1
def readfullauto(self, reg=0x8c):
"""Reads visible + IR diode from the I2C device with auto ranging"""
try:
fullval = self.i2c.readU16(reg)
newval = self.i2c.reverseByteOrder(fullval)
if newval >= 37177:
self.i2c.write8(0x81, 0x01)
time.sleep(self.pause)
fullval = self.i2c.readU16(reg)
newval = self.i2c.reverseByteOrder(fullval)
if (self.debug):
print("I2C: Device 0x%02X returned 0x%04X from reg 0x%02X" % (self.address, fullval & 0xFFFF, reg))
return newval
except IOError:
print("Error accessing 0x%02X: Check your I2C address" % self.address)
return -1
def readIRauto(self, reg=0x8e):
"""Reads IR diode from the I2C device with auto ranging"""
try:
IRval = self.i2c.readU16(reg)
newIR = self.i2c.reverseByteOrder(IRval)
if newIR >= 37177:
self.i2c.write8(0x81, 0x01) # remove 16x gain
time.sleep(self.pause)
IRval = self.i2c.readU16(reg)
newIR = self.i2c.reverseByteOrder(IRval)
if (self.debug):
print("I2C: Device 0x%02X returned 0x%04X from reg 0x%02X" % (self.address, IRval & 0xFFFF, reg))
return newIR
except IOError:
print("Error accessing 0x%02X: Check your I2C address" % self.address)
return -1
def luxread(address = 0x39, debug = False, autorange = True):
"""Grabs a lux reading either with autoranging or without"""
LuxSensor = Luxmeter(0x39, False)
if autorange == True:
ambient = LuxSensor.readfullauto()
IR = LuxSensor.readIRauto()
else:
ambient = LuxSensor.readfull()
IR = LuxSensor.readIR()
ratio = (float) (IR / ambient)
if ((ratio >= 0) & (ratio <= 0.52)):
lux = (0.0315 * ambient) - (0.0593 * ambient * (ratio**1.4))
elif (ratio <= 0.65):
lux = (0.0229 * ambient) - (0.0291 * IR)
elif (ratio <= 0.80):
lux = (0.0157 * ambient) - (0.018 + IR)
elif (ratio <= 1.3):
lux = (0.00338 * ambient) - (0.0026 * IR)
elif (ratio > 1.3):
lux = 0
return lux
print(luxread())
I just mounted the sensor in my external sensor pod. I'm going to see how it performs over a couple of days.
Let me know if you have any suggestions.
Thanks,
Static
-
- Posts: 13
- Joined: Mon Jan 14, 2013 2:47 pm
Re: TSL2561 and Raspberry Pi
Static: I am wondering why your math changed from the first code you wrote for the sensor and the most recent one.
- static
- Posts: 188
- Joined: Thu Dec 23, 2010 6:21 pm
Re: TSL2561 and Raspberry Pi
Which math?
The code I pulled really was from pandring's code (earlier in the thread you posted in), but was largely taken from bryand's code in this thread:
http://forums.adafruit.com/viewtopic.ph ... 33#p179633
I did a couple of tweaks, but it's mostly theirs.
The code I pulled really was from pandring's code (earlier in the thread you posted in), but was largely taken from bryand's code in this thread:
http://forums.adafruit.com/viewtopic.ph ... 33#p179633
I did a couple of tweaks, but it's mostly theirs.
-
- Posts: 13
- Joined: Mon Jan 14, 2013 2:47 pm
Re: TSL2561 and Raspberry Pi
Sorry, Static. I didn't realize that was bryand's code you had posted in your last comment. I was just comparing your getLux function to his luxread function with the if/else statements and ratios, but it's a trivial question now.
I tried your code with our application of saving values into a .csv file and it worked, but ran into the same problem of getting 0s when the light was too bright. I will try bryand's code myself now - fingers crossed.
I tried your code with our application of saving values into a .csv file and it worked, but ran into the same problem of getting 0s when the light was too bright. I will try bryand's code myself now - fingers crossed.
Please be positive and constructive with your questions and comments.