Skip to content

Commit 501c1ce

Browse files
committedMay 6, 2013
Merge pull request adafruit#42 from jwcooper/master
Add TCS34725
2 parents baccabb + d1a0487 commit 501c1ce

File tree

3 files changed

+413
-0
lines changed

3 files changed

+413
-0
lines changed
 

‎Adafruit_TCS34725/Adafruit_I2C.py

+170
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
#!/usr/bin/python
2+
3+
import smbus
4+
5+
# ===========================================================================
6+
# Adafruit_I2C Class
7+
# ===========================================================================
8+
9+
class Adafruit_I2C :
10+
11+
@staticmethod
12+
def getPiRevision():
13+
"Gets the version number of the Raspberry Pi board"
14+
# Courtesy quick2wire-python-api
15+
# https://github.com/quick2wire/quick2wire-python-api
16+
try:
17+
with open('/proc/cpuinfo','r') as f:
18+
for line in f:
19+
if line.startswith('Revision'):
20+
return 1 if line.rstrip()[-1] in ['1','2'] else 2
21+
except:
22+
return 0
23+
24+
@staticmethod
25+
def getPiI2CBusNumber():
26+
# Gets the I2C bus number /dev/i2c#
27+
return 1 if Adafruit_I2C.getPiRevision() > 1 else 0
28+
29+
def __init__(self, address, busnum=-1, debug=False):
30+
self.address = address
31+
# By default, the correct I2C bus is auto-detected using /proc/cpuinfo
32+
# Alternatively, you can hard-code the bus version below:
33+
# self.bus = smbus.SMBus(0); # Force I2C0 (early 256MB Pi's)
34+
# self.bus = smbus.SMBus(1); # Force I2C1 (512MB Pi's)
35+
self.bus = smbus.SMBus(
36+
busnum if busnum >= 0 else Adafruit_I2C.getPiI2CBusNumber())
37+
self.debug = debug
38+
39+
def reverseByteOrder(self, data):
40+
"Reverses the byte order of an int (16-bit) or long (32-bit) value"
41+
# Courtesy Vishal Sapre
42+
byteCount = len(hex(data)[2:].replace('L','')[::2])
43+
val = 0
44+
for i in range(byteCount):
45+
val = (val << 8) | (data & 0xff)
46+
data >>= 8
47+
return val
48+
49+
def errMsg(self):
50+
print "Error accessing 0x%02X: Check your I2C address" % self.address
51+
return -1
52+
53+
def write8(self, reg, value):
54+
"Writes an 8-bit value to the specified register/address"
55+
try:
56+
self.bus.write_byte_data(self.address, reg, value)
57+
if self.debug:
58+
print "I2C: Wrote 0x%02X to register 0x%02X" % (value, reg)
59+
except IOError, err:
60+
return self.errMsg()
61+
62+
def write16(self, reg, value):
63+
"Writes a 16-bit value to the specified register/address pair"
64+
try:
65+
self.bus.write_word_data(self.address, reg, value)
66+
if self.debug:
67+
print ("I2C: Wrote 0x%02X to register pair 0x%02X,0x%02X" %
68+
(value, reg, reg+1))
69+
except IOError, err:
70+
return self.errMsg()
71+
72+
def writeList(self, reg, list):
73+
"Writes an array of bytes using I2C format"
74+
try:
75+
if self.debug:
76+
print "I2C: Writing list to register 0x%02X:" % reg
77+
print list
78+
self.bus.write_i2c_block_data(self.address, reg, list)
79+
except IOError, err:
80+
return self.errMsg()
81+
82+
def readList(self, reg, length):
83+
"Read a list of bytes from the I2C device"
84+
try:
85+
results = self.bus.read_i2c_block_data(self.address, reg, length)
86+
if self.debug:
87+
print ("I2C: Device 0x%02X returned the following from reg 0x%02X" %
88+
(self.address, reg))
89+
print results
90+
return results
91+
except IOError, err:
92+
return self.errMsg()
93+
94+
def readU8(self, reg):
95+
"Read an unsigned byte from the I2C device"
96+
try:
97+
result = self.bus.read_byte_data(self.address, reg)
98+
if self.debug:
99+
print ("I2C: Device 0x%02X returned 0x%02X from reg 0x%02X" %
100+
(self.address, result & 0xFF, reg))
101+
return result
102+
except IOError, err:
103+
return self.errMsg()
104+
105+
def readS8(self, reg):
106+
"Reads a signed byte from the I2C device"
107+
try:
108+
result = self.bus.read_byte_data(self.address, reg)
109+
if result > 127: result -= 256
110+
if self.debug:
111+
print ("I2C: Device 0x%02X returned 0x%02X from reg 0x%02X" %
112+
(self.address, result & 0xFF, reg))
113+
return result
114+
except IOError, err:
115+
return self.errMsg()
116+
117+
def readU16(self, reg):
118+
"Reads an unsigned 16-bit value from the I2C device"
119+
try:
120+
hibyte = self.readU8(reg)
121+
lobyte = self.readU8(reg+1)
122+
result = (hibyte << 8) + lobyte
123+
if (self.debug):
124+
print "I2C: Device 0x%02X returned 0x%04X from reg 0x%02X" % (self.address, result & 0xFFFF, reg)
125+
return result
126+
except IOError, err:
127+
return self.errMsg()
128+
129+
def readS16(self, reg):
130+
"Reads a signed 16-bit value from the I2C device"
131+
try:
132+
hibyte = self.readS8(reg)
133+
lobyte = self.readU8(reg+1)
134+
result = (hibyte << 8) + lobyte
135+
if (self.debug):
136+
print "I2C: Device 0x%02X returned 0x%04X from reg 0x%02X" % (self.address, result & 0xFFFF, reg)
137+
return result
138+
except IOError, err:
139+
return self.errMsg()
140+
141+
def readU16Rev(self, reg):
142+
"Reads an unsigned 16-bit value from the I2C device with rev byte order"
143+
try:
144+
lobyte = self.readU8(reg)
145+
hibyte = self.readU8(reg+1)
146+
result = (hibyte << 8) + lobyte
147+
if (self.debug):
148+
print "I2C: Device 0x%02X returned 0x%04X from reg 0x%02X" % (self.address, result & 0xFFFF, reg)
149+
return result
150+
except IOError, err:
151+
return self.errMsg()
152+
153+
def readS16Rev(self, reg):
154+
"Reads a signed 16-bit value from the I2C device with rev byte order"
155+
try:
156+
lobyte = self.readS8(reg)
157+
hibyte = self.readU8(reg+1)
158+
result = (hibyte << 8) + lobyte
159+
if (self.debug):
160+
print "I2C: Device 0x%02X returned 0x%04X from reg 0x%02X" % (self.address, result & 0xFFFF, reg)
161+
return result
162+
except IOError, err:
163+
return self.errMsg()
164+
165+
if __name__ == '__main__':
166+
try:
167+
bus = Adafruit_I2C(address=0)
168+
print "Default I2C bus is accessible"
169+
except:
170+
print "Error accessing default I2C bus"
+220
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,220 @@
1+
#!/usr/bin/python
2+
3+
import time
4+
from Adafruit_I2C import Adafruit_I2C
5+
6+
# ===========================================================================
7+
# TCS3472 Class
8+
# ===========================================================================
9+
10+
11+
class TCS34725:
12+
i2c = None
13+
14+
__TCS34725_ADDRESS = 0x29
15+
__TCS34725_ID = 0x12 # 0x44 = TCS34721/TCS34725, 0x4D = TCS34723/TCS34727
16+
17+
__TCS34725_COMMAND_BIT = 0x80
18+
19+
__TCS34725_ENABLE = 0x00
20+
__TCS34725_ENABLE_AIEN = 0x10 # RGBC Interrupt Enable
21+
__TCS34725_ENABLE_WEN = 0x08 # Wait enable - Writing 1 activates the wait timer
22+
__TCS34725_ENABLE_AEN = 0x02 # RGBC Enable - Writing 1 actives the ADC, 0 disables it
23+
__TCS34725_ENABLE_PON = 0x01 # Power on - Writing 1 activates the internal oscillator, 0 disables it
24+
__TCS34725_ATIME = 0x01 # Integration time
25+
__TCS34725_WTIME = 0x03 # Wait time (if TCS34725_ENABLE_WEN is asserted)
26+
__TCS34725_WTIME_2_4MS = 0xFF # WLONG0 = 2.4ms WLONG1 = 0.029s
27+
__TCS34725_WTIME_204MS = 0xAB # WLONG0 = 204ms WLONG1 = 2.45s
28+
__TCS34725_WTIME_614MS = 0x00 # WLONG0 = 614ms WLONG1 = 7.4s
29+
__TCS34725_AILTL = 0x04 # Clear channel lower interrupt threshold
30+
__TCS34725_AILTH = 0x05
31+
__TCS34725_AIHTL = 0x06 # Clear channel upper interrupt threshold
32+
__TCS34725_AIHTH = 0x07
33+
__TCS34725_PERS = 0x0C # Persistence register - basic SW filtering mechanism for interrupts
34+
__TCS34725_PERS_NONE = 0b0000 # Every RGBC cycle generates an interrupt
35+
__TCS34725_PERS_1_CYCLE = 0b0001 # 1 clean channel value outside threshold range generates an interrupt
36+
__TCS34725_PERS_2_CYCLE = 0b0010 # 2 clean channel values outside threshold range generates an interrupt
37+
__TCS34725_PERS_3_CYCLE = 0b0011 # 3 clean channel values outside threshold range generates an interrupt
38+
__TCS34725_PERS_5_CYCLE = 0b0100 # 5 clean channel values outside threshold range generates an interrupt
39+
__TCS34725_PERS_10_CYCLE = 0b0101 # 10 clean channel values outside threshold range generates an interrupt
40+
__TCS34725_PERS_15_CYCLE = 0b0110 # 15 clean channel values outside threshold range generates an interrupt
41+
__TCS34725_PERS_20_CYCLE = 0b0111 # 20 clean channel values outside threshold range generates an interrupt
42+
__TCS34725_PERS_25_CYCLE = 0b1000 # 25 clean channel values outside threshold range generates an interrupt
43+
__TCS34725_PERS_30_CYCLE = 0b1001 # 30 clean channel values outside threshold range generates an interrupt
44+
__TCS34725_PERS_35_CYCLE = 0b1010 # 35 clean channel values outside threshold range generates an interrupt
45+
__TCS34725_PERS_40_CYCLE = 0b1011 # 40 clean channel values outside threshold range generates an interrupt
46+
__TCS34725_PERS_45_CYCLE = 0b1100 # 45 clean channel values outside threshold range generates an interrupt
47+
__TCS34725_PERS_50_CYCLE = 0b1101 # 50 clean channel values outside threshold range generates an interrupt
48+
__TCS34725_PERS_55_CYCLE = 0b1110 # 55 clean channel values outside threshold range generates an interrupt
49+
__TCS34725_PERS_60_CYCLE = 0b1111 # 60 clean channel values outside threshold range generates an interrupt
50+
__TCS34725_CONFIG = 0x0D
51+
__TCS34725_CONFIG_WLONG = 0x02 # Choose between short and long (12x) wait times via TCS34725_WTIME
52+
__TCS34725_CONTROL = 0x0F # Set the gain level for the sensor
53+
__TCS34725_ID = 0x12 # 0x44 = TCS34721/TCS34725, 0x4D = TCS34723/TCS34727
54+
__TCS34725_STATUS = 0x13
55+
__TCS34725_STATUS_AINT = 0x10 # RGBC Clean channel interrupt
56+
__TCS34725_STATUS_AVALID = 0x01 # Indicates that the RGBC channels have completed an integration cycle
57+
58+
__TCS34725_CDATAL = 0x14 # Clear channel data
59+
__TCS34725_CDATAH = 0x15
60+
__TCS34725_RDATAL = 0x16 # Red channel data
61+
__TCS34725_RDATAH = 0x17
62+
__TCS34725_GDATAL = 0x18 # Green channel data
63+
__TCS34725_GDATAH = 0x19
64+
__TCS34725_BDATAL = 0x1A # Blue channel data
65+
__TCS34725_BDATAH = 0x1B
66+
67+
__TCS34725_INTEGRATIONTIME_2_4MS = 0xFF # 2.4ms - 1 cycle - Max Count: 1024
68+
__TCS34725_INTEGRATIONTIME_24MS = 0xF6 # 24ms - 10 cycles - Max Count: 10240
69+
__TCS34725_INTEGRATIONTIME_50MS = 0xEB # 50ms - 20 cycles - Max Count: 20480
70+
__TCS34725_INTEGRATIONTIME_101MS = 0xD5 # 101ms - 42 cycles - Max Count: 43008
71+
__TCS34725_INTEGRATIONTIME_154MS = 0xC0 # 154ms - 64 cycles - Max Count: 65535
72+
__TCS34725_INTEGRATIONTIME_700MS = 0x00 # 700ms - 256 cycles - Max Count: 65535
73+
74+
__TCS34725_GAIN_1X = 0x00 # No gain
75+
__TCS34725_GAIN_4X = 0x01 # 2x gain
76+
__TCS34725_GAIN_16X = 0x02 # 16x gain
77+
__TCS34725_GAIN_60X = 0x03 # 60x gain
78+
79+
__integrationTimeDelay = {
80+
0xFF: 0.0024, # 2.4ms - 1 cycle - Max Count: 1024
81+
0xF6: 0.024, # 24ms - 10 cycles - Max Count: 10240
82+
0xEB: 0.050, # 50ms - 20 cycles - Max Count: 20480
83+
0xD5: 0.101, # 101ms - 42 cycles - Max Count: 43008
84+
0xC0: 0.154, # 154ms - 64 cycles - Max Count: 65535
85+
0x00: 0.700 # 700ms - 256 cycles - Max Count: 65535
86+
}
87+
88+
# Private Methods
89+
def __readU8(self, reg):
90+
return self.i2c.readU8(self.__TCS34725_COMMAND_BIT | reg)
91+
92+
def __readU16Rev(self, reg):
93+
return self.i2c.readU16Rev(self.__TCS34725_COMMAND_BIT | reg)
94+
95+
def __write8(self, reg, value):
96+
self.i2c.write8(self.__TCS34725_COMMAND_BIT | reg, value & 0xff)
97+
98+
# Constructor
99+
def __init__(self, address=0x29, debug=False, integrationTime=0xFF, gain=0x01):
100+
self.i2c = Adafruit_I2C(address)
101+
102+
self.address = address
103+
self.debug = debug
104+
self.integrationTime = integrationTime
105+
self.initialize(integrationTime, gain)
106+
107+
def initialize(self, integrationTime, gain):
108+
"Initializes I2C and configures the sensor (call this function before \
109+
doing anything else)"
110+
# Make sure we're actually connected
111+
result = self.__readU8(self.__TCS34725_ID)
112+
if (result != 0x44):
113+
return -1
114+
115+
# Set default integration time and gain
116+
self.setIntegrationTime(integrationTime)
117+
self.setGain(gain)
118+
119+
# Note: by default, the device is in power down mode on bootup
120+
self.enable()
121+
122+
def enable(self):
123+
self.__write8(self.__TCS34725_ENABLE, self.__TCS34725_ENABLE_PON)
124+
time.sleep(0.01)
125+
self.__write8(self.__TCS34725_ENABLE, (self.__TCS34725_ENABLE_PON | self.__TCS34725_ENABLE_AEN))
126+
127+
def disable(self):
128+
reg = 0
129+
reg = self.__readU8(self.__TCS34725_ENABLE)
130+
self.__write8(self.__TCS34725_ENABLE, (reg & ~(self.__TCS34725_ENABLE_PON | self.__TCS34725_ENABLE_AEN)))
131+
132+
def setIntegrationTime(self, integrationTime):
133+
"Sets the integration time for the TC34725"
134+
self.integrationTime = integrationTime
135+
136+
self.__write8(self.__TCS34725_ATIME, integrationTime)
137+
138+
def getIntegrationTime(self):
139+
return self.__readU8(self.__TCS34725_ATIME)
140+
141+
def setGain(self, gain):
142+
"Adjusts the gain on the TCS34725 (adjusts the sensitivity to light)"
143+
self.__write8(self.__TCS34725_CONTROL, gain)
144+
145+
def getGain(self):
146+
return self.__readU8(self.__TCS34725_CONTROL)
147+
148+
def getRawData(self):
149+
"Reads the raw red, green, blue and clear channel values"
150+
151+
color = {}
152+
153+
color["r"] = self.__readU16Rev(self.__TCS34725_RDATAL)
154+
color["b"] = self.__readU16Rev(self.__TCS34725_BDATAL)
155+
color["g"] = self.__readU16Rev(self.__TCS34725_GDATAL)
156+
color["c"] = self.__readU16Rev(self.__TCS34725_CDATAL)
157+
158+
# Set a delay for the integration time
159+
delay = self.__integrationTimeDelay.get(self.integrationTime)
160+
time.sleep(delay)
161+
162+
return color
163+
164+
def setInterrupt(self, int):
165+
r = self.__readU8(self.__TCS34725_ENABLE)
166+
167+
if (int):
168+
r |= self.__TCS34725_ENABLE_AIEN
169+
else:
170+
r &= ~self.__TCS34725_ENABLE_AIEN
171+
172+
self.__write8(self.__TCS34725_ENABLE, r)
173+
174+
def clearInterrupt(self):
175+
self.i2c.write8(0x66 & 0xff)
176+
177+
def setIntLimits(self, low, high):
178+
self.i2c.write8(0x04, low & 0xFF)
179+
self.i2c.write8(0x05, low >> 8)
180+
self.i2c.write8(0x06, high & 0xFF)
181+
self.i2c.write8(0x07, high >> 8)
182+
183+
#Static Utility Methods
184+
@staticmethod
185+
def calculateColorTemperature(rgb):
186+
"Converts the raw R/G/B values to color temperature in degrees Kelvin"
187+
188+
if not isinstance(rgb, dict):
189+
raise ValueError('calculateColorTemperature expects dict as parameter')
190+
191+
# 1. Map RGB values to their XYZ counterparts.
192+
# Based on 6500K fluorescent, 3000K fluorescent
193+
# and 60W incandescent values for a wide range.
194+
# Note: Y = Illuminance or lux
195+
X = (-0.14282 * rgb['r']) + (1.54924 * rgb['g']) + (-0.95641 * rgb['b'])
196+
Y = (-0.32466 * rgb['r']) + (1.57837 * rgb['g']) + (-0.73191 * rgb['b'])
197+
Z = (-0.68202 * rgb['r']) + (0.77073 * rgb['g']) + ( 0.56332 * rgb['b'])
198+
199+
# 2. Calculate the chromaticity co-ordinates
200+
xc = (X) / (X + Y + Z)
201+
yc = (Y) / (X + Y + Z)
202+
203+
# 3. Use McCamy's formula to determine the CCT
204+
n = (xc - 0.3320) / (0.1858 - yc)
205+
206+
# Calculate the final CCT
207+
cct = (449.0 * (n ** 3.0)) + (3525.0 *(n ** 2.0)) + (6823.3 * n) + 5520.33
208+
209+
return int(cct)
210+
211+
@staticmethod
212+
def calculateLux(rgb):
213+
"Converts the raw R/G/B values to color temperature in degrees Kelvin"
214+
215+
if not isinstance(rgb, dict):
216+
raise ValueError('calculateLux expects dict as parameter')
217+
218+
illuminance = (-0.32466 * rgb['r']) + (1.57837 * rgb['g']) + (-0.73191 * rgb['b'])
219+
220+
return int(illuminance)

0 commit comments

Comments
 (0)
Please sign in to comment.