From 916d6751fa11ed8945d6470c1d1069968087227e Mon Sep 17 00:00:00 2001
From: thomas <thomas.vadebout@mailo.com>
Date: Sun, 27 Jun 2021 22:55:26 +0200
Subject: [PATCH] add color sensors

---
 include/Adafruit_TCS34725.h | 200 +++++++++++++
 src/Adafruit_TCS34725.cpp   | 556 ++++++++++++++++++++++++++++++++++++
 src/main.cpp                | 116 ++++++++
 3 files changed, 872 insertions(+)
 create mode 100644 include/Adafruit_TCS34725.h
 create mode 100644 src/Adafruit_TCS34725.cpp

diff --git a/include/Adafruit_TCS34725.h b/include/Adafruit_TCS34725.h
new file mode 100644
index 0000000..46d5875
--- /dev/null
+++ b/include/Adafruit_TCS34725.h
@@ -0,0 +1,200 @@
+/*!
+ *  @file Adafruit_TCS34725.h
+ *
+ *  Software License Agreement (BSD License)
+ *
+ *  Copyright (c) 2013, Adafruit Industries
+ *  All rights reserved.
+ *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions are
+ *  met:
+ *  1. Redistributions of source code must retain the above copyright
+ *  notice, this list of conditions and the following disclaimer.
+ *  2. Redistributions in binary form must reproduce the above copyright
+ *  notice, this list of conditions and the following disclaimer in the
+ *  documentation and/or other materials provided with the distribution.
+ *  3. Neither the name of the copyright holders nor the
+ *  names of its contributors may be used to endorse or promote products
+ *  derived from this software without specific prior written permission.
+ *
+ *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
+ *  EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ *  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ *  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
+ *  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ *  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ *  SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ *  OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ *  DAMAGE.
+ */
+#ifndef _TCS34725_H_
+#define _TCS34725_H_
+
+#include <Arduino.h>
+
+#include <Wire.h>
+
+#define TCS34725_ADDRESS (0x29)     /**< I2C address **/
+#define TCS34725_COMMAND_BIT (0x80) /**< Command bit **/
+#define TCS34725_ENABLE (0x00)      /**< Interrupt Enable register */
+#define TCS34725_ENABLE_AIEN (0x10) /**< RGBC Interrupt Enable */
+#define TCS34725_ENABLE_WEN                                                    \
+  (0x08) /**< Wait Enable - Writing 1 activates the wait timer */
+#define TCS34725_ENABLE_AEN                                                    \
+  (0x02) /**< RGBC Enable - Writing 1 actives the ADC, 0 disables it */
+#define TCS34725_ENABLE_PON                                                    \
+  (0x01) /**< Power on - Writing 1 activates the internal oscillator, 0        \
+            disables it */
+#define TCS34725_ATIME (0x01) /**< Integration time */
+#define TCS34725_WTIME                                                         \
+  (0x03) /**< Wait time (if TCS34725_ENABLE_WEN is asserted) */
+#define TCS34725_WTIME_2_4MS (0xFF) /**< WLONG0 = 2.4ms   WLONG1 = 0.029s */
+#define TCS34725_WTIME_204MS (0xAB) /**< WLONG0 = 204ms   WLONG1 = 2.45s  */
+#define TCS34725_WTIME_614MS (0x00) /**< WLONG0 = 614ms   WLONG1 = 7.4s   */
+#define TCS34725_AILTL                                                         \
+  (0x04) /**< Clear channel lower interrupt threshold (lower byte) */
+#define TCS34725_AILTH                                                         \
+  (0x05) /**< Clear channel lower interrupt threshold (higher byte) */
+#define TCS34725_AIHTL                                                         \
+  (0x06) /**< Clear channel upper interrupt threshold (lower byte) */
+#define TCS34725_AIHTH                                                         \
+  (0x07) /**< Clear channel upper interrupt threshold (higher byte) */
+#define TCS34725_PERS                                                          \
+  (0x0C) /**< Persistence register - basic SW filtering mechanism for          \
+            interrupts */
+#define TCS34725_PERS_NONE                                                     \
+  (0b0000) /**< Every RGBC cycle generates an interrupt */
+#define TCS34725_PERS_1_CYCLE                                                  \
+  (0b0001) /**< 1 clean channel value outside threshold range generates an     \
+              interrupt */
+#define TCS34725_PERS_2_CYCLE                                                  \
+  (0b0010) /**< 2 clean channel values outside threshold range generates an    \
+              interrupt */
+#define TCS34725_PERS_3_CYCLE                                                  \
+  (0b0011) /**< 3 clean channel values outside threshold range generates an    \
+              interrupt */
+#define TCS34725_PERS_5_CYCLE                                                  \
+  (0b0100) /**< 5 clean channel values outside threshold range generates an    \
+              interrupt */
+#define TCS34725_PERS_10_CYCLE                                                 \
+  (0b0101) /**< 10 clean channel values outside threshold range generates an   \
+              interrupt*/
+#define TCS34725_PERS_15_CYCLE                                                 \
+  (0b0110) /**< 15 clean channel values outside threshold range generates an   \
+              interrupt*/
+#define TCS34725_PERS_20_CYCLE                                                 \
+  (0b0111) /**< 20 clean channel values outside threshold range generates an   \
+              interrupt*/
+#define TCS34725_PERS_25_CYCLE                                                 \
+  (0b1000) /**< 25 clean channel values outside threshold range generates an   \
+              interrupt*/
+#define TCS34725_PERS_30_CYCLE                                                 \
+  (0b1001) /**< 30 clean channel values outside threshold range generates an   \
+              interrupt*/
+#define TCS34725_PERS_35_CYCLE                                                 \
+  (0b1010) /**< 35 clean channel values outside threshold range generates an   \
+              interrupt*/
+#define TCS34725_PERS_40_CYCLE                                                 \
+  (0b1011) /**< 40 clean channel values outside threshold range generates an   \
+              interrupt*/
+#define TCS34725_PERS_45_CYCLE                                                 \
+  (0b1100) /**< 45 clean channel values outside threshold range generates an   \
+              interrupt*/
+#define TCS34725_PERS_50_CYCLE                                                 \
+  (0b1101) /**< 50 clean channel values outside threshold range generates an   \
+              interrupt*/
+#define TCS34725_PERS_55_CYCLE                                                 \
+  (0b1110) /**< 55 clean channel values outside threshold range generates an   \
+              interrupt*/
+#define TCS34725_PERS_60_CYCLE                                                 \
+  (0b1111) /**< 60 clean channel values outside threshold range generates an   \
+              interrupt*/
+#define TCS34725_CONFIG (0x0D) /**< Configuration **/
+#define TCS34725_CONFIG_WLONG                                                  \
+  (0x02) /**< Choose between short and long (12x) wait times via               \
+            TCS34725_WTIME */
+#define TCS34725_CONTROL (0x0F) /**< Set the gain level for the sensor */
+#define TCS34725_ID                                                            \
+  (0x12) /**< 0x44 = TCS34721/TCS34725, 0x4D = TCS34723/TCS34727 */
+#define TCS34725_STATUS (0x13)      /**< Device status **/
+#define TCS34725_STATUS_AINT (0x10) /**< RGBC Clean channel interrupt */
+#define TCS34725_STATUS_AVALID                                                 \
+  (0x01) /**< Indicates that the RGBC channels have completed an integration   \
+            cycle */
+#define TCS34725_CDATAL (0x14) /**< Clear channel data low byte */
+#define TCS34725_CDATAH (0x15) /**< Clear channel data high byte */
+#define TCS34725_RDATAL (0x16) /**< Red channel data low byte */
+#define TCS34725_RDATAH (0x17) /**< Red channel data high byte */
+#define TCS34725_GDATAL (0x18) /**< Green channel data low byte */
+#define TCS34725_GDATAH (0x19) /**< Green channel data high byte */
+#define TCS34725_BDATAL (0x1A) /**< Blue channel data low byte */
+#define TCS34725_BDATAH (0x1B) /**< Blue channel data high byte */
+
+/** Integration time settings for TCS34725 */
+typedef enum {
+  TCS34725_INTEGRATIONTIME_2_4MS =
+      0xFF, /**<  2.4ms - 1 cycle    - Max Count: 1024  */
+  TCS34725_INTEGRATIONTIME_24MS =
+      0xF6, /**<  24ms  - 10 cycles  - Max Count: 10240 */
+  TCS34725_INTEGRATIONTIME_50MS =
+      0xEB, /**<  50ms  - 20 cycles  - Max Count: 20480 */
+  TCS34725_INTEGRATIONTIME_101MS =
+      0xD5, /**<  101ms - 42 cycles  - Max Count: 43008 */
+  TCS34725_INTEGRATIONTIME_154MS =
+      0xC0, /**<  154ms - 64 cycles  - Max Count: 65535 */
+  TCS34725_INTEGRATIONTIME_700MS =
+      0x00 /**<  700ms - 256 cycles - Max Count: 65535 */
+} tcs34725IntegrationTime_t;
+
+/** Gain settings for TCS34725  */
+typedef enum {
+  TCS34725_GAIN_1X = 0x00,  /**<  No gain  */
+  TCS34725_GAIN_4X = 0x01,  /**<  4x gain  */
+  TCS34725_GAIN_16X = 0x02, /**<  16x gain */
+  TCS34725_GAIN_60X = 0x03  /**<  60x gain */
+} tcs34725Gain_t;
+
+/*!
+ *  @brief  Class that stores state and functions for interacting with
+ *          TCS34725 Color Sensor
+ */
+class Adafruit_TCS34725 {
+public:
+  Adafruit_TCS34725(tcs34725IntegrationTime_t = TCS34725_INTEGRATIONTIME_2_4MS,
+                    tcs34725Gain_t = TCS34725_GAIN_1X);
+
+  boolean begin(uint8_t addr, TwoWire *theWire);
+  boolean begin(uint8_t addr);
+  boolean begin();
+  boolean init();
+
+  void setIntegrationTime(tcs34725IntegrationTime_t it);
+  void setGain(tcs34725Gain_t gain);
+  void getRawData(uint16_t *r, uint16_t *g, uint16_t *b, uint16_t *c);
+  void getRGB(float *r, float *g, float *b);
+  void getRawDataOneShot(uint16_t *r, uint16_t *g, uint16_t *b, uint16_t *c);
+  uint16_t calculateColorTemperature(uint16_t r, uint16_t g, uint16_t b);
+  uint16_t calculateColorTemperature_dn40(uint16_t r, uint16_t g, uint16_t b,
+                                          uint16_t c);
+  uint16_t calculateLux(uint16_t r, uint16_t g, uint16_t b);
+  void write8(uint8_t reg, uint32_t value);
+  uint8_t read8(uint8_t reg);
+  uint16_t read16(uint8_t reg);
+  void setInterrupt(boolean flag);
+  void clearInterrupt();
+  void setIntLimits(uint16_t l, uint16_t h);
+  void enable();
+  void disable();
+
+private:
+  TwoWire *_wire;
+  uint8_t _i2caddr;
+  boolean _tcs34725Initialised;
+  tcs34725Gain_t _tcs34725Gain;
+  tcs34725IntegrationTime_t _tcs34725IntegrationTime;
+};
+
+#endif
diff --git a/src/Adafruit_TCS34725.cpp b/src/Adafruit_TCS34725.cpp
new file mode 100644
index 0000000..4438113
--- /dev/null
+++ b/src/Adafruit_TCS34725.cpp
@@ -0,0 +1,556 @@
+/*!
+ *  @file Adafruit_TCS34725.cpp
+ *
+ *  @mainpage Driver for the TCS34725 digital color sensors.
+ *
+ *  @section intro_sec Introduction
+ *
+ *  Adafruit invests time and resources providing this open source code,
+ *  please support Adafruit and open-source hardware by purchasing
+ *  products from Adafruit!
+ *
+ *  @section author Author
+ *
+ *  KTOWN (Adafruit Industries)
+ *
+ *  @section license License
+ *
+ *  BSD (see license.txt)
+ *
+ *  @section HISTORY
+ *
+ *  v1.0 - First release
+ */
+
+#define ARDUINO 200
+
+#include <math.h>
+#include <stdlib.h>
+
+#include "Adafruit_TCS34725.h"
+
+/*!
+ *  @brief  Implements missing powf function
+ *  @param  x
+ *          Base number
+ *  @param  y
+ *          Exponent
+ *  @return x raised to the power of y
+ */
+float powf(const float x, const float y) {
+  return (float)(pow((double)x, (double)y));
+}
+
+/*!
+ *  @brief  Writes a register and an 8 bit value over I2C
+ *  @param  reg
+ *  @param  value
+ */
+void Adafruit_TCS34725::write8(uint8_t reg, uint32_t value) {
+  _wire->beginTransmission(_i2caddr);
+#if ARDUINO >= 100
+  _wire->write(TCS34725_COMMAND_BIT | reg);
+  _wire->write(value & 0xFF);
+#else
+  _wire->send(TCS34725_COMMAND_BIT | reg);
+  _wire->send(value & 0xFF);
+#endif
+  _wire->endTransmission();
+}
+
+/*!
+ *  @brief  Reads an 8 bit value over I2C
+ *  @param  reg
+ *  @return value
+ */
+uint8_t Adafruit_TCS34725::read8(uint8_t reg) {
+  _wire->beginTransmission(_i2caddr);
+#if ARDUINO >= 100
+  _wire->write(TCS34725_COMMAND_BIT | reg);
+#else
+  _wire->send(TCS34725_COMMAND_BIT | reg);
+#endif
+  _wire->endTransmission();
+
+  _wire->requestFrom(_i2caddr, (uint8_t)1);
+#if ARDUINO >= 100
+  return _wire->read();
+#else
+  return _wire->receive();
+#endif
+}
+
+/*!
+ *  @brief  Reads a 16 bit values over I2C
+ *  @param  reg
+ *  @return value
+ */
+uint16_t Adafruit_TCS34725::read16(uint8_t reg) {
+  uint16_t x;
+  uint16_t t;
+
+  _wire->beginTransmission(_i2caddr);
+#if ARDUINO >= 100
+  _wire->write(TCS34725_COMMAND_BIT | reg);
+#else
+  _wire->send(TCS34725_COMMAND_BIT | reg);
+#endif
+  _wire->endTransmission();
+
+  _wire->requestFrom(_i2caddr, (uint8_t)2);
+#if ARDUINO >= 100
+  t = _wire->read();
+  x = _wire->read();
+#else
+  t = _wire->receive();
+  x = _wire->receive();
+#endif
+  x <<= 8;
+  x |= t;
+  return x;
+}
+
+/*!
+ *  @brief  Enables the device
+ */
+void Adafruit_TCS34725::enable() {
+  write8(TCS34725_ENABLE, TCS34725_ENABLE_PON);
+  delay(3);
+  write8(TCS34725_ENABLE, TCS34725_ENABLE_PON | TCS34725_ENABLE_AEN);
+  /* Set a delay for the integration time.
+    This is only necessary in the case where enabling and then
+    immediately trying to read values back. This is because setting
+    AEN triggers an automatic integration, so if a read RGBC is
+    performed too quickly, the data is not yet valid and all 0's are
+    returned */
+  switch (_tcs34725IntegrationTime) {
+  case TCS34725_INTEGRATIONTIME_2_4MS:
+    delay(3);
+    break;
+  case TCS34725_INTEGRATIONTIME_24MS:
+    delay(24);
+    break;
+  case TCS34725_INTEGRATIONTIME_50MS:
+    delay(50);
+    break;
+  case TCS34725_INTEGRATIONTIME_101MS:
+    delay(101);
+    break;
+  case TCS34725_INTEGRATIONTIME_154MS:
+    delay(154);
+    break;
+  case TCS34725_INTEGRATIONTIME_700MS:
+    delay(700);
+    break;
+  }
+}
+
+/*!
+ *  @brief  Disables the device (putting it in lower power sleep mode)
+ */
+void Adafruit_TCS34725::disable() {
+  /* Turn the device off to save power */
+  uint8_t reg = 0;
+  reg = read8(TCS34725_ENABLE);
+  write8(TCS34725_ENABLE, reg & ~(TCS34725_ENABLE_PON | TCS34725_ENABLE_AEN));
+}
+
+/*!
+ *  @brief  Constructor
+ *  @param  it
+ *          Integration Time
+ *  @param  gain
+ *          Gain
+ */
+Adafruit_TCS34725::Adafruit_TCS34725(tcs34725IntegrationTime_t it,
+                                     tcs34725Gain_t gain) {
+  _tcs34725Initialised = false;
+  _tcs34725IntegrationTime = it;
+  _tcs34725Gain = gain;
+}
+
+/*!
+ *  @brief  Initializes I2C and configures the sensor
+ *  @param  addr
+ *          i2c address
+ *  @return True if initialization was successful, otherwise false.
+ */
+boolean Adafruit_TCS34725::begin(uint8_t addr) {
+  _i2caddr = addr;
+  _wire = &Wire;
+
+  return init();
+}
+
+/*!
+ *  @brief  Initializes I2C and configures the sensor
+ *  @param  addr
+ *          i2c address
+ *  @param  *theWire
+ *          The Wire object
+ *  @return True if initialization was successful, otherwise false.
+ */
+boolean Adafruit_TCS34725::begin(uint8_t addr, TwoWire *theWire) {
+  _i2caddr = addr;
+  _wire = theWire;
+
+  return init();
+}
+
+/*!
+ *  @brief  Initializes I2C and configures the sensor
+ *  @return True if initialization was successful, otherwise false.
+ */
+boolean Adafruit_TCS34725::begin() {
+  _i2caddr = TCS34725_ADDRESS;
+  _wire = &Wire;
+
+  return init();
+}
+
+/*!
+ *  @brief  Part of begin
+ *  @return True if initialization was successful, otherwise false.
+ */
+boolean Adafruit_TCS34725::init() {
+  _wire->begin();
+
+  /* Make sure we're actually connected */
+  uint8_t x = read8(TCS34725_ID);
+  if ((x != 0x4d) && (x != 0x44) && (x != 0x10)) {
+    return false;
+  }
+  _tcs34725Initialised = true;
+
+  /* Set default integration time and gain */
+  setIntegrationTime(_tcs34725IntegrationTime);
+  setGain(_tcs34725Gain);
+
+  /* Note: by default, the device is in power down mode on bootup */
+  enable();
+
+  return true;
+}
+
+/*!
+ *  @brief  Sets the integration time for the TC34725
+ *  @param  it
+ *          Integration Time
+ */
+void Adafruit_TCS34725::setIntegrationTime(tcs34725IntegrationTime_t it) {
+  if (!_tcs34725Initialised)
+    begin();
+
+  /* Update the timing register */
+  write8(TCS34725_ATIME, it);
+
+  /* Update value placeholders */
+  _tcs34725IntegrationTime = it;
+}
+
+/*!
+ *  @brief  Adjusts the gain on the TCS34725
+ *  @param  gain
+ *          Gain (sensitivity to light)
+ */
+void Adafruit_TCS34725::setGain(tcs34725Gain_t gain) {
+  if (!_tcs34725Initialised)
+    begin();
+
+  /* Update the timing register */
+  write8(TCS34725_CONTROL, gain);
+
+  /* Update value placeholders */
+  _tcs34725Gain = gain;
+}
+
+/*!
+ *  @brief  Reads the raw red, green, blue and clear channel values
+ *  @param  *r
+ *          Red value
+ *  @param  *g
+ *          Green value
+ *  @param  *b
+ *          Blue value
+ *  @param  *c
+ *          Clear channel value
+ */
+void Adafruit_TCS34725::getRawData(uint16_t *r, uint16_t *g, uint16_t *b,
+                                   uint16_t *c) {
+  if (!_tcs34725Initialised)
+    begin();
+
+  *c = read16(TCS34725_CDATAL);
+  *r = read16(TCS34725_RDATAL);
+  *g = read16(TCS34725_GDATAL);
+  *b = read16(TCS34725_BDATAL);
+
+  /* Set a delay for the integration time */
+  switch (_tcs34725IntegrationTime) {
+  case TCS34725_INTEGRATIONTIME_2_4MS:
+    delay(3);
+    break;
+  case TCS34725_INTEGRATIONTIME_24MS:
+    delay(24);
+    break;
+  case TCS34725_INTEGRATIONTIME_50MS:
+    delay(50);
+    break;
+  case TCS34725_INTEGRATIONTIME_101MS:
+    delay(101);
+    break;
+  case TCS34725_INTEGRATIONTIME_154MS:
+    delay(154);
+    break;
+  case TCS34725_INTEGRATIONTIME_700MS:
+    delay(700);
+    break;
+  }
+}
+
+/*!
+ *  @brief  Reads the raw red, green, blue and clear channel values in
+ *          one-shot mode (e.g., wakes from sleep, takes measurement, enters
+ *          sleep)
+ *  @param  *r
+ *          Red value
+ *  @param  *g
+ *          Green value
+ *  @param  *b
+ *          Blue value
+ *  @param  *c
+ *          Clear channel value
+ */
+void Adafruit_TCS34725::getRawDataOneShot(uint16_t *r, uint16_t *g, uint16_t *b,
+                                          uint16_t *c) {
+  if (!_tcs34725Initialised)
+    begin();
+
+  enable();
+  getRawData(r, g, b, c);
+  disable();
+}
+
+/*!
+ *  @brief  Read the RGB color detected by the sensor.
+ *  @param  *r
+ *          Red value normalized to 0-255
+ *  @param  *g
+ *          Green value normalized to 0-255
+ *  @param  *b
+ *          Blue value normalized to 0-255
+ */
+void Adafruit_TCS34725::getRGB(float *r, float *g, float *b) {
+  uint16_t red, green, blue, clear;
+  getRawData(&red, &green, &blue, &clear);
+  uint32_t sum = clear;
+
+  // Avoid divide by zero errors ... if clear = 0 return black
+  if (clear == 0) {
+    *r = *g = *b = 0;
+    return;
+  }
+
+  *r = (float)red / sum * 255.0;
+  *g = (float)green / sum * 255.0;
+  *b = (float)blue / sum * 255.0;
+}
+
+/*!
+ *  @brief  Converts the raw R/G/B values to color temperature in degrees Kelvin
+ *  @param  r
+ *          Red value
+ *  @param  g
+ *          Green value
+ *  @param  b
+ *          Blue value
+ *  @return Color temperature in degrees Kelvin
+ */
+uint16_t Adafruit_TCS34725::calculateColorTemperature(uint16_t r, uint16_t g,
+                                                      uint16_t b) {
+  float X, Y, Z; /* RGB to XYZ correlation      */
+  float xc, yc;  /* Chromaticity co-ordinates   */
+  float n;       /* McCamy's formula            */
+  float cct;
+
+  if (r == 0 && g == 0 && b == 0) {
+    return 0;
+  }
+
+  /* 1. Map RGB values to their XYZ counterparts.    */
+  /* Based on 6500K fluorescent, 3000K fluorescent   */
+  /* and 60W incandescent values for a wide range.   */
+  /* Note: Y = Illuminance or lux                    */
+  X = (-0.14282F * r) + (1.54924F * g) + (-0.95641F * b);
+  Y = (-0.32466F * r) + (1.57837F * g) + (-0.73191F * b);
+  Z = (-0.68202F * r) + (0.77073F * g) + (0.56332F * b);
+
+  /* 2. Calculate the chromaticity co-ordinates      */
+  xc = (X) / (X + Y + Z);
+  yc = (Y) / (X + Y + Z);
+
+  /* 3. Use McCamy's formula to determine the CCT    */
+  n = (xc - 0.3320F) / (0.1858F - yc);
+
+  /* Calculate the final CCT */
+  cct =
+      (449.0F * powf(n, 3)) + (3525.0F * powf(n, 2)) + (6823.3F * n) + 5520.33F;
+
+  /* Return the results in degrees Kelvin */
+  return (uint16_t)cct;
+}
+
+/*!
+ *  @brief  Converts the raw R/G/B values to color temperature in degrees
+ *          Kelvin using the algorithm described in DN40 from Taos (now AMS).
+ *  @param  r
+ *          Red value
+ *  @param  g
+ *          Green value
+ *  @param  b
+ *          Blue value
+ *  @param  c
+ *          Clear channel value
+ *  @return Color temperature in degrees Kelvin
+ */
+uint16_t Adafruit_TCS34725::calculateColorTemperature_dn40(uint16_t r,
+                                                           uint16_t g,
+                                                           uint16_t b,
+                                                           uint16_t c) {
+  uint16_t r2, b2; /* RGB values minus IR component */
+  uint16_t sat;    /* Digital saturation level */
+  uint16_t ir;     /* Inferred IR content */
+
+  if (c == 0) {
+    return 0;
+  }
+
+  /* Analog/Digital saturation:
+   *
+   * (a) As light becomes brighter, the clear channel will tend to
+   *     saturate first since R+G+B is approximately equal to C.
+   * (b) The TCS34725 accumulates 1024 counts per 2.4ms of integration
+   *     time, up to a maximum values of 65535. This means analog
+   *     saturation can occur up to an integration time of 153.6ms
+   *     (64*2.4ms=153.6ms).
+   * (c) If the integration time is > 153.6ms, digital saturation will
+   *     occur before analog saturation. Digital saturation occurs when
+   *     the count reaches 65535.
+   */
+  if ((256 - _tcs34725IntegrationTime) > 63) {
+    /* Track digital saturation */
+    sat = 65535;
+  } else {
+    /* Track analog saturation */
+    sat = 1024 * (256 - _tcs34725IntegrationTime);
+  }
+
+  /* Ripple rejection:
+   *
+   * (a) An integration time of 50ms or multiples of 50ms are required to
+   *     reject both 50Hz and 60Hz ripple.
+   * (b) If an integration time faster than 50ms is required, you may need
+   *     to average a number of samples over a 50ms period to reject ripple
+   *     from fluorescent and incandescent light sources.
+   *
+   * Ripple saturation notes:
+   *
+   * (a) If there is ripple in the received signal, the value read from C
+   *     will be less than the max, but still have some effects of being
+   *     saturated. This means that you can be below the 'sat' value, but
+   *     still be saturating. At integration times >150ms this can be
+   *     ignored, but <= 150ms you should calculate the 75% saturation
+   *     level to avoid this problem.
+   */
+  if ((256 - _tcs34725IntegrationTime) <= 63) {
+    /* Adjust sat to 75% to avoid analog saturation if atime < 153.6ms */
+    sat -= sat / 4;
+  }
+
+  /* Check for saturation and mark the sample as invalid if true */
+  if (c >= sat) {
+    return 0;
+  }
+
+  /* AMS RGB sensors have no IR channel, so the IR content must be */
+  /* calculated indirectly. */
+  ir = (r + g + b > c) ? (r + g + b - c) / 2 : 0;
+
+  /* Remove the IR component from the raw RGB values */
+  r2 = r - ir;
+  b2 = b - ir;
+
+  if (r2 == 0) {
+    return 0;
+  }
+
+  /* A simple method of measuring color temp is to use the ratio of blue */
+  /* to red light, taking IR cancellation into account. */
+  uint16_t cct = (3810 * (uint32_t)b2) / /** Color temp coefficient. */
+                     (uint32_t)r2 +
+                 1391; /** Color temp offset. */
+
+  return cct;
+}
+
+/*!
+ *  @brief  Converts the raw R/G/B values to lux
+ *  @param  r
+ *          Red value
+ *  @param  g
+ *          Green value
+ *  @param  b
+ *          Blue value
+ *  @return Lux value
+ */
+uint16_t Adafruit_TCS34725::calculateLux(uint16_t r, uint16_t g, uint16_t b) {
+  float illuminance;
+
+  /* This only uses RGB ... how can we integrate clear or calculate lux */
+  /* based exclusively on clear since this might be more reliable?      */
+  illuminance = (-0.32466F * r) + (1.57837F * g) + (-0.73191F * b);
+
+  return (uint16_t)illuminance;
+}
+
+/*!
+ *  @brief  Sets interrupt for TCS34725
+ *  @param  i
+ *          Interrupt (True/False)
+ */
+void Adafruit_TCS34725::setInterrupt(boolean i) {
+  uint8_t r = read8(TCS34725_ENABLE);
+  if (i) {
+    r |= TCS34725_ENABLE_AIEN;
+  } else {
+    r &= ~TCS34725_ENABLE_AIEN;
+  }
+  write8(TCS34725_ENABLE, r);
+}
+
+/*!
+ *  @brief  Clears inerrupt for TCS34725
+ */
+void Adafruit_TCS34725::clearInterrupt() {
+  _wire->beginTransmission(_i2caddr);
+#if ARDUINO >= 100
+  _wire->write(TCS34725_COMMAND_BIT | 0x66);
+#else
+  _wire->send(TCS34725_COMMAND_BIT | 0x66);
+#endif
+  _wire->endTransmission();
+}
+
+/*!
+ *  @brief  Sets inerrupt limits
+ *  @param  low
+ *          Low limit
+ *  @param  high
+ *          High limit
+ */
+void Adafruit_TCS34725::setIntLimits(uint16_t low, uint16_t high) {
+  write8(0x04, low & 0xFF);
+  write8(0x05, low >> 8);
+  write8(0x06, high & 0xFF);
+  write8(0x07, high >> 8);
+}
diff --git a/src/main.cpp b/src/main.cpp
index d4a7f3e..0b81865 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -4,9 +4,23 @@
 
 #include <Servo.h>
 
+#include "Adafruit_TCS34725.h"
+
+
+
+
 #include <ros.h>
 #include <std_msgs/Bool.h>
 #include <std_msgs/Int32.h>
+#include <geometry_msgs/Vector3.h>
+
+// color sensors
+#define COL_L 4
+#define COL_R 7
+Adafruit_TCS34725 tcs = Adafruit_TCS34725(TCS34725_INTEGRATIONTIME_24MS, TCS34725_GAIN_1X);
+ros::NodeHandle node_handle;
+geometry_msgs::Vector3 hsv_msg;
+
 
 // Servo object declaration
 Servo flagServo; 
@@ -82,6 +96,17 @@ ros::Publisher teamStatusPub("team", &teamMsg);
 ros::Publisher buttonStatusPub("button_status", &buttonStatusMsg);
 ros::Publisher bauStatusPub("BAU_status", &bauStatusMsg);
 ros::Publisher pullCordStatusPub("pull_cord_status", &pullCordStatusMsg);
+ros::Publisher color_sensor_left("color_sensor/left", &hsv_msg);
+ros::Publisher color_sensor_right("color_sensor/right", &hsv_msg);
+
+
+void TCA9548A(uint8_t bus)
+{
+  Wire.beginTransmission(0x70);  // TCA9548A address is 0x70
+  Wire.write(1 << bus);          // send byte to select bus
+  Wire.endTransmission();
+}
+
 
 void estimatedScoreCallback(const std_msgs::Int32 &estimatedScore);
 ros::Subscriber<std_msgs::Int32> estimatedScoreSub("estimated_score", &estimatedScoreCallback);
@@ -115,8 +140,28 @@ void refreshScreen()
   lcd.print(buttonStatus ? "ON" : "OFF");
 }
 
+void setupColorSensors(){
+
+  TCA9548A(COL_L);
+
+  if (tcs.begin()) {
+    nh.advertise(color_sensor_left);
+    nh.loginfo("Found left color sensor");
+  } else {
+    nh.logerror("Left sensor not found");
+  }
 
 
+  TCA9548A(COL_R);
+
+  if (tcs.begin()) {
+    nh.loginfo("Found right color sensor");
+    nh.advertise(color_sensor_right);
+  } else {
+    nh.logerror("Right sensor not found");
+  }
+}
+
 void setup()
 {
   flagServo.attach(flagServoPin);
@@ -139,6 +184,7 @@ void setup()
   buttonStatus = digitalRead(buttonPin);
 
   nh.initNode();
+
   nh.advertise(teamStatusPub);
   nh.advertise(buttonStatusPub);
   nh.advertise(pullCordStatusPub);
@@ -148,6 +194,9 @@ void setup()
   nh.subscribe(flagStatusSub);
   nh.subscribe(bauSoftSub);
 
+  // color Sensors setup
+  setupColorSensors();
+
   lcd.clear();
   lcd.setCursor(0, 0);
   lcd.print("Waiting ROS...");
@@ -203,6 +252,69 @@ void manage_supply_card_data(){
 
 }
 
+float max(float a, float b, float c) {
+   return ((a > b)? (a > c ? a : c) : (b > c ? b : c));
+}
+float min(float a, float b, float c) {
+   return ((a < b)? (a < c ? a : c) : (b < c ? b : c));
+}
+
+int rgb_to_hsv(float& h, float& s,float& v, uint16_t re,uint16_t gr,uint16_t bl){
+
+
+   float r = ((float) re) / (255.0);
+   float g = ((float) gr) / (255.0);
+   float b = ((float) bl) / (255.0);
+
+   float cmax = max(r, g, b); // maximum of r, g, b
+   float cmin = min(r, g, b); // minimum of r, g, b
+   float diff = cmax-cmin; // diff of cmax and cmin.
+
+   if (cmax == cmin)
+      h = 0;
+   else if (cmax == r)
+      h = fmod((60 * ((g - b) / diff) + 360), 360.0);
+   else if (cmax == g)
+      h = fmod((60 * ((b - r) / diff) + 120), 360.0);
+   else if (cmax == b)
+      h = fmod((60 * ((r - g) / diff) + 240), 360.0);
+   // if cmax equal zero
+      if (cmax == 0)
+         s = 0;
+      else
+         s = (diff / cmax) * 100;
+   // compute v
+   v = cmax * 100;
+
+   return 0;
+}
+
+void colorSensorsLoop(){
+  uint16_t r, g, b, c, colorTemp, lux;
+  float h, s, v;
+
+  TCA9548A(COL_L);
+
+  tcs.getRawData(&r, &g, &b, &c);
+  rgb_to_hsv(h, s, v, r, g, b);
+
+  hsv_msg.x = h;
+  hsv_msg.y = s;
+  hsv_msg.z = v;
+
+  color_sensor_left.publish( &hsv_msg );
+
+  TCA9548A(COL_R);
+
+  tcs.getRawData(&r, &g, &b, &c);
+  rgb_to_hsv(h, s, v, r, g, b);
+
+  hsv_msg.x = h;
+  hsv_msg.y = s;
+  hsv_msg.z = v;
+
+  color_sensor_right.publish( &hsv_msg );
+}
 
 void loop()
 {
@@ -222,6 +334,10 @@ void loop()
     refreshScreen();
   }
 
+
+  // color Sensors loop
+  colorSensorsLoop();
+
   // DEBUT PARTIE TIRETTE
 
   int pullCordReading = digitalRead(pullCordPin);
-- 
GitLab