ADDR = 0x29
REG_CMD = 0b10000000
REG_CMD_AUTO_INC = 0b00100000
REG_CLEAR_L = REG_CMD | REG_CMD_AUTO_INC | 0x14
REG_RED_L = REG_CMD | REG_CMD_AUTO_INC | 0x16
REG_GREEN_L = REG_CMD | REG_CMD_AUTO_INC | 0x18
REG_BLUE_L = REG_CMD | REG_CMD_AUTO_INC | 0x1A
REG_ENABLE = REG_CMD | 0
REG_ATIME = REG_CMD | 1
REG_CONTROL = REG_CMD | 0x0f
REG_STATUS = REG_CMD | 0x13
REG_CONTROL_GAIN_1X = 0b00000000
REG_CONTROL_GAIN_4X = 0b00000001
REG_CONTROL_GAIN_16X = 0b00000010
REG_CONTROL_GAIN_60X = 0b00000011
REG_ENABLE_INTERRUPT = 1 << 4
REG_ENABLE_WAIT = 1 << 3
REG_ENABLE_RGBC = 1 << 1
REG_ENABLE_POWER = 1
CH_RED = 0
CH_GREEN = 1
CH_BLUE = 2
CH_CLEAR = 3
class tcs3472:
def __init__(self, i2c_bus=None, addr=ADDR):
self.addr = addr
self.i2c_bus = i2c_bus
if not hasattr(i2c_bus, "read_word_data") or not hasattr(i2c_bus, "write_byte_data"):
raise TypeError("Object given for i2c_bus must implement read_word_data and write_byte_data")
self.i2c_bus.write_byte_data(ADDR, REG_ENABLE, REG_ENABLE_RGBC | REG_ENABLE_POWER)
self.set_integration_time_ms(511.2)
def set_integration_time_ms(self, ms):
"""Set the sensor integration time in milliseconds.
:param ms: The integration time in milliseconds from 2.4 to 612, in increments of 2.4.
"""
if ms < 2.4 or ms > 612:
raise TypeError("Integration time must be between 2.4 and 612ms")
self._atime = int(round(ms / 2.4))
self._max_count = min(65535, (256 - self._atime) * 1024)
self.i2c_bus.write_byte_data(ADDR, REG_ATIME, 256 - self._atime)
def max_count(self):
"""Return the maximum value which can be counted by a channel with the chosen integration time."""
return self._max_count
def scaled(self):
"""Return a tuple containing the red, green and blue colour values ranging from 0 to 1.0 scaled against the clear value."""
rgbc = self.raw()
if rgbc[CH_CLEAR] > 0:
return tuple([float(x) / rgbc[CH_CLEAR] for x in rgbc])
return (0,0,0)
def rgb(self):
"""Return a tuple containing the red, green and blue colour values ranging 0 to 255 scaled against the clear value."""
return tuple([int(x * 255) for x in self.scaled()][:CH_CLEAR])
def light(self):
"""Return the clear/unfiltered light level as an integer."""
return self.raw()[CH_CLEAR]
def valid(self):
return (self.i2c_bus.read_byte_data(ADDR, REG_STATUS) & 1) > 0
def raw(self):
"""Return the raw red, green, blue and clear channels"""
#data = self.i2c_bus.read_i2c_block_data(ADDR, REG_CLEAR_L, 8)
#c = data[0] | (data[1] << 8)
#r = data[2] | (data[3] << 8)
#g = data[4] | (data[5] << 8)
#b = data[6] | (data[7] << 8)
c = self.i2c_bus.read_word_data(ADDR, REG_CLEAR_L)
r = self.i2c_bus.read_word_data(ADDR, REG_RED_L)
g = self.i2c_bus.read_word_data(ADDR, REG_GREEN_L)
b = self.i2c_bus.read_word_data(ADDR, REG_BLUE_L)
return (r, g, b, c)