lux.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421
  1. #include <stdio.h>
  2. #include "freertos/FreeRTOS.h"
  3. #include "freertos/task.h"
  4. #include "esp_system.h"
  5. #include "driver/gpio.h"
  6. #include "driver/i2c.h"
  7. #include "esp_log.h"
  8. #include "sdkconfig.h"
  9. #include "lux.h"
  10. #include "mqtt.h"
  11. #include "config.h"
  12. // Code from:
  13. // https://github.com/espressif/esp-idf/blob/release/v4.4/examples/peripherals/i2c/i2c_simple/main/i2c_simple_main.c
  14. #ifdef ENABLE_LUX_SENSOR
  15. static const char *TAG = "LUX";
  16. #include <stdbool.h>
  17. bool _tsl2561AutoGain = true;
  18. tsl2561IntegrationTime_t _tsl2561IntegrationTime = TSL2561_INTEGRATIONTIME_101MS;
  19. tsl2561Gain_t _tsl2561Gain = TSL2561_GAIN_1X;
  20. #define I2C_MASTER_SCL_IO I2C_MASTER_SCL /*!< GPIO number used for I2C master clock */
  21. #define I2C_MASTER_SDA_IO I2C_MASTER_SDA /*!< GPIO number used for I2C master data */
  22. #define I2C_MASTER_NUM 0 /*!< I2C master i2c port number, the number of i2c peripheral interfaces available will depend on the chip */
  23. #define I2C_MASTER_FREQ_HZ 400000 /*!< I2C master clock frequency */
  24. #define I2C_MASTER_TX_BUF_DISABLE 0 /*!< I2C master doesn't need buffer */
  25. #define I2C_MASTER_RX_BUF_DISABLE 0 /*!< I2C master doesn't need buffer */
  26. #define I2C_MASTER_TIMEOUT_MS 1000
  27. /** TSL2561 I2C Registers */
  28. enum {
  29. TSL2561_REGISTER_CONTROL = 0x00, // Control/power register
  30. TSL2561_REGISTER_TIMING = 0x01, // Set integration time register
  31. TSL2561_REGISTER_THRESHHOLDL_LOW = 0x02, // Interrupt low threshold low-byte
  32. TSL2561_REGISTER_THRESHHOLDL_HIGH = 0x03, // Interrupt low threshold high-byte
  33. TSL2561_REGISTER_THRESHHOLDH_LOW = 0x04, // Interrupt high threshold low-byte
  34. TSL2561_REGISTER_THRESHHOLDH_HIGH = 0x05, // Interrupt high threshold high-byte
  35. TSL2561_REGISTER_INTERRUPT = 0x06, // Interrupt settings
  36. TSL2561_REGISTER_CRC = 0x08, // Factory use only
  37. TSL2561_REGISTER_ID = 0x0A, // TSL2561 identification setting
  38. TSL2561_REGISTER_CHAN0_LOW = 0x0C, // Light data channel 0, low byte
  39. TSL2561_REGISTER_CHAN0_HIGH = 0x0D, // Light data channel 0, high byte
  40. TSL2561_REGISTER_CHAN1_LOW = 0x0E, // Light data channel 1, low byte
  41. TSL2561_REGISTER_CHAN1_HIGH = 0x0F // Light data channel 1, high byte
  42. };
  43. static esp_err_t i2c_master_init(void)
  44. {
  45. int i2c_master_port = I2C_MASTER_NUM;
  46. i2c_config_t conf = {
  47. .mode = I2C_MODE_MASTER,
  48. .sda_io_num = I2C_MASTER_SDA_IO,
  49. .scl_io_num = I2C_MASTER_SCL_IO,
  50. .sda_pullup_en = GPIO_PULLUP_ENABLE,
  51. .scl_pullup_en = GPIO_PULLUP_ENABLE,
  52. .master.clk_speed = I2C_MASTER_FREQ_HZ,
  53. };
  54. i2c_param_config(i2c_master_port, &conf);
  55. return i2c_driver_install(i2c_master_port, conf.mode, I2C_MASTER_RX_BUF_DISABLE, I2C_MASTER_TX_BUF_DISABLE, 0);
  56. }
  57. static esp_err_t tsl2561_register_read(uint8_t reg_addr, uint8_t *data, size_t len)
  58. {
  59. return i2c_master_write_read_device(I2C_MASTER_NUM, CONFIG_TSL2561_I2C_ADDRESS, &reg_addr, 1, data, len, I2C_MASTER_TIMEOUT_MS / portTICK_RATE_MS);
  60. }
  61. void write8(uint8_t reg, uint8_t value)
  62. {
  63. uint8_t data[2];
  64. data[0] = reg;
  65. data[1] = value;
  66. i2c_master_write_to_device(I2C_MASTER_NUM, CONFIG_TSL2561_I2C_ADDRESS, data, 2, I2C_MASTER_TIMEOUT_MS / portTICK_RATE_MS);
  67. }
  68. uint16_t read16(uint8_t reg)
  69. {
  70. uint8_t data[2];
  71. tsl2561_register_read(reg, data, 2);
  72. return (data[1] << 8) | data[0];
  73. }
  74. uint8_t read8(uint8_t reg)
  75. {
  76. uint8_t data;
  77. tsl2561_register_read(reg, &data, 1);
  78. return data;
  79. }
  80. void setIntegrationTime(tsl2561IntegrationTime_t time)
  81. {
  82. /* Enable the device by setting the control bit to 0x03 */
  83. /* Update the timing register */
  84. write8(TSL2561_COMMAND_BIT | TSL2561_REGISTER_TIMING, time | _tsl2561Gain);
  85. /* Update value placeholders */
  86. _tsl2561IntegrationTime = time;
  87. }
  88. void setGain(tsl2561Gain_t gain)
  89. {
  90. /* Update the timing register */
  91. write8(TSL2561_COMMAND_BIT | TSL2561_REGISTER_TIMING, _tsl2561IntegrationTime | gain);
  92. /* Update value placeholders */
  93. _tsl2561Gain = gain;
  94. }
  95. void enableAutoRange(bool enable)
  96. {
  97. _tsl2561AutoGain = enable ? true : false;
  98. }
  99. void enable(void)
  100. {
  101. /* Enable the device by setting the control bit to 0x03 */
  102. write8(TSL2561_COMMAND_BIT | TSL2561_REGISTER_CONTROL, TSL2561_CONTROL_POWERON);
  103. }
  104. void delay(uint32_t ms)
  105. {
  106. vTaskDelay(ms / portTICK_RATE_MS);
  107. }
  108. void getData (uint16_t *broadband, uint16_t *ir)
  109. {
  110. /* Wait x ms for ADC to complete */
  111. switch (_tsl2561IntegrationTime)
  112. {
  113. case TSL2561_INTEGRATIONTIME_13MS:
  114. delay(TSL2561_DELAY_INTTIME_13MS); // KTOWN: Was 14ms
  115. break;
  116. case TSL2561_INTEGRATIONTIME_101MS:
  117. delay(TSL2561_DELAY_INTTIME_101MS); // KTOWN: Was 102ms
  118. break;
  119. default:
  120. delay(TSL2561_DELAY_INTTIME_402MS); // KTOWN: Was 403ms
  121. break;
  122. }
  123. /* Reads a two byte value from channel 0 (visible + infrared) */
  124. *broadband = read16(TSL2561_COMMAND_BIT | TSL2561_WORD_BIT | TSL2561_REGISTER_CHAN0_LOW);
  125. /* Reads a two byte value from channel 1 (infrared) */
  126. *ir = read16(TSL2561_COMMAND_BIT | TSL2561_WORD_BIT | TSL2561_REGISTER_CHAN1_LOW);
  127. }
  128. void getLuminosity (uint16_t *broadband, uint16_t *ir)
  129. {
  130. bool valid = false;
  131. /* If Auto gain disabled get a single reading and continue */
  132. if(!_tsl2561AutoGain)
  133. {
  134. getData (broadband, ir);
  135. return;
  136. }
  137. /* Read data until we find a valid range */
  138. bool _agcCheck = false;
  139. do
  140. {
  141. uint16_t _b, _ir;
  142. uint16_t _hi, _lo;
  143. tsl2561IntegrationTime_t _it = _tsl2561IntegrationTime;
  144. /* Get the hi/low threshold for the current integration time */
  145. switch(_it)
  146. {
  147. case TSL2561_INTEGRATIONTIME_13MS:
  148. _hi = TSL2561_AGC_THI_13MS;
  149. _lo = TSL2561_AGC_TLO_13MS;
  150. break;
  151. case TSL2561_INTEGRATIONTIME_101MS:
  152. _hi = TSL2561_AGC_THI_101MS;
  153. _lo = TSL2561_AGC_TLO_101MS;
  154. break;
  155. default:
  156. _hi = TSL2561_AGC_THI_402MS;
  157. _lo = TSL2561_AGC_TLO_402MS;
  158. break;
  159. }
  160. getData(&_b, &_ir);
  161. /* Run an auto-gain check if we haven't already done so ... */
  162. if (!_agcCheck)
  163. {
  164. if ((_b < _lo) && (_tsl2561Gain == TSL2561_GAIN_1X))
  165. {
  166. /* Increase the gain and try again */
  167. setGain(TSL2561_GAIN_16X);
  168. /* Drop the previous conversion results */
  169. getData(&_b, &_ir);
  170. /* Set a flag to indicate we've adjusted the gain */
  171. _agcCheck = true;
  172. }
  173. else if ((_b > _hi) && (_tsl2561Gain == TSL2561_GAIN_16X))
  174. {
  175. /* Drop gain to 1x and try again */
  176. setGain(TSL2561_GAIN_1X);
  177. /* Drop the previous conversion results */
  178. getData(&_b, &_ir);
  179. /* Set a flag to indicate we've adjusted the gain */
  180. _agcCheck = true;
  181. }
  182. else
  183. {
  184. /* Nothing to look at here, keep moving ....
  185. Reading is either valid, or we're already at the chips limits */
  186. *broadband = _b;
  187. *ir = _ir;
  188. valid = true;
  189. }
  190. }
  191. else
  192. {
  193. /* If we've already adjusted the gain once, just return the new results.
  194. This avoids endless loops where a value is at one extreme pre-gain,
  195. and the the other extreme post-gain */
  196. *broadband = _b;
  197. *ir = _ir;
  198. valid = true;
  199. }
  200. } while (!valid);
  201. }
  202. uint32_t calculateLux(uint16_t broadband, uint16_t ir)
  203. {
  204. unsigned long chScale;
  205. unsigned long channel1;
  206. unsigned long channel0;
  207. /* Make sure the sensor isn't saturated! */
  208. uint16_t clipThreshold;
  209. switch (_tsl2561IntegrationTime)
  210. {
  211. case TSL2561_INTEGRATIONTIME_13MS:
  212. clipThreshold = TSL2561_CLIPPING_13MS;
  213. break;
  214. case TSL2561_INTEGRATIONTIME_101MS:
  215. clipThreshold = TSL2561_CLIPPING_101MS;
  216. break;
  217. default:
  218. clipThreshold = TSL2561_CLIPPING_402MS;
  219. break;
  220. }
  221. /* Return 65536 lux if the sensor is saturated */
  222. if ((broadband > clipThreshold) || (ir > clipThreshold))
  223. {
  224. return 65536;
  225. }
  226. /* Get the correct scale depending on the intergration time */
  227. switch (_tsl2561IntegrationTime)
  228. {
  229. case TSL2561_INTEGRATIONTIME_13MS:
  230. chScale = TSL2561_LUX_CHSCALE_TINT0;
  231. break;
  232. case TSL2561_INTEGRATIONTIME_101MS:
  233. chScale = TSL2561_LUX_CHSCALE_TINT1;
  234. break;
  235. default: /* No scaling ... integration time = 402ms */
  236. chScale = (1 << TSL2561_LUX_CHSCALE);
  237. break;
  238. }
  239. /* Scale for gain (1x or 16x) */
  240. if (!_tsl2561Gain) chScale = chScale << 4;
  241. /* Scale the channel values */
  242. channel0 = (broadband * chScale) >> TSL2561_LUX_CHSCALE;
  243. channel1 = (ir * chScale) >> TSL2561_LUX_CHSCALE;
  244. /* Find the ratio of the channel values (Channel1/Channel0) */
  245. unsigned long ratio1 = 0;
  246. if (channel0 != 0) ratio1 = (channel1 << (TSL2561_LUX_RATIOSCALE+1)) / channel0;
  247. /* round the ratio value */
  248. unsigned long ratio = (ratio1 + 1) >> 1;
  249. unsigned int b, m;
  250. #ifdef TSL2561_PACKAGE_CS
  251. if ((ratio >= 0) && (ratio <= TSL2561_LUX_K1C))
  252. {b=TSL2561_LUX_B1C; m=TSL2561_LUX_M1C;}
  253. else if (ratio <= TSL2561_LUX_K2C)
  254. {b=TSL2561_LUX_B2C; m=TSL2561_LUX_M2C;}
  255. else if (ratio <= TSL2561_LUX_K3C)
  256. {b=TSL2561_LUX_B3C; m=TSL2561_LUX_M3C;}
  257. else if (ratio <= TSL2561_LUX_K4C)
  258. {b=TSL2561_LUX_B4C; m=TSL2561_LUX_M4C;}
  259. else if (ratio <= TSL2561_LUX_K5C)
  260. {b=TSL2561_LUX_B5C; m=TSL2561_LUX_M5C;}
  261. else if (ratio <= TSL2561_LUX_K6C)
  262. {b=TSL2561_LUX_B6C; m=TSL2561_LUX_M6C;}
  263. else if (ratio <= TSL2561_LUX_K7C)
  264. {b=TSL2561_LUX_B7C; m=TSL2561_LUX_M7C;}
  265. else if (ratio > TSL2561_LUX_K8C)
  266. {b=TSL2561_LUX_B8C; m=TSL2561_LUX_M8C;}
  267. #else
  268. if ((ratio >= 0) && (ratio <= TSL2561_LUX_K1T))
  269. {b=TSL2561_LUX_B1T; m=TSL2561_LUX_M1T;}
  270. else if (ratio <= TSL2561_LUX_K2T)
  271. {b=TSL2561_LUX_B2T; m=TSL2561_LUX_M2T;}
  272. else if (ratio <= TSL2561_LUX_K3T)
  273. {b=TSL2561_LUX_B3T; m=TSL2561_LUX_M3T;}
  274. else if (ratio <= TSL2561_LUX_K4T)
  275. {b=TSL2561_LUX_B4T; m=TSL2561_LUX_M4T;}
  276. else if (ratio <= TSL2561_LUX_K5T)
  277. {b=TSL2561_LUX_B5T; m=TSL2561_LUX_M5T;}
  278. else if (ratio <= TSL2561_LUX_K6T)
  279. {b=TSL2561_LUX_B6T; m=TSL2561_LUX_M6T;}
  280. else if (ratio <= TSL2561_LUX_K7T)
  281. {b=TSL2561_LUX_B7T; m=TSL2561_LUX_M7T;}
  282. else if (ratio > TSL2561_LUX_K8T)
  283. {b=TSL2561_LUX_B8T; m=TSL2561_LUX_M8T;}
  284. #endif
  285. unsigned long temp;
  286. temp = ((channel0 * b) - (channel1 * m));
  287. /* Do not allow negative lux value */
  288. if (temp < 0) temp = 0;
  289. /* Round lsb (2^(LUX_SCALE-1)) */
  290. temp += (1 << (TSL2561_LUX_LUXSCALE-1));
  291. /* Strip off fractional portion */
  292. uint32_t lux = temp >> TSL2561_LUX_LUXSCALE;
  293. /* Signal I2C had no errors */
  294. return lux;
  295. }
  296. uint32_t readLuxSensor(void)
  297. {
  298. uint16_t broadband;
  299. uint16_t ir;
  300. getLuminosity(&broadband, &ir);
  301. uint32_t lux = calculateLux(broadband, ir);
  302. if( lux > 65000 ) lux=65000; // Set a maximum value
  303. return lux;
  304. }
  305. static void tsl2561_task(void * pvParameter)
  306. {
  307. uint8_t data[2];
  308. static uint32_t totalLux = 0;
  309. static uint16_t loopCnt = 0;
  310. TickType_t vLastWakeTime = xTaskGetTickCount();
  311. ESP_ERROR_CHECK(i2c_master_init());
  312. ESP_LOGI(TAG, "I2C initialized successfully");
  313. delay(200);
  314. enable();
  315. delay(200);
  316. /* Read the TSL2561_REGISTER_ID register, on power up the register should have the value 0x05
  317. The returned value consists of:
  318. Bit 7:4 = Part number
  319. Bit 3:0 = Revision number
  320. 0x50 = TSL2561T/FN/CL Rev:0
  321. */
  322. uint8_t id = read8(TSL2561_COMMAND_BIT | TSL2561_REGISTER_ID);
  323. ESP_LOGI(TAG, "WHO_AM_I = %02X", id);
  324. setIntegrationTime(TSL2561_INTEGRATIONTIME_402MS);
  325. setGain(TSL2561_GAIN_1X);
  326. // Do an initial delay to make the different tasks to work out of sync to each other (not send all data at same time)
  327. vTaskDelayUntil( &vLastWakeTime, 5000 / portTICK_PERIOD_MS );
  328. while (1)
  329. {
  330. uint32_t lux = readLuxSensor();
  331. totalLux += lux;
  332. loopCnt++;
  333. ESP_LOGI(TAG, "Lux: %u", lux);
  334. // Once every minute, calc mean lux and send to server.
  335. if( loopCnt == 6 ) {
  336. char mqtt_s[50];
  337. char value_s[10];
  338. totalLux /= 6;
  339. sprintf(mqtt_s,"garage/lux");
  340. sprintf(value_s,"%u",totalLux);
  341. ESP_LOGI(TAG, "Topic:%s Data:%s", mqtt_s, value_s);
  342. sendMQTTMessage(mqtt_s, value_s);
  343. totalLux = 0;
  344. loopCnt = 0;
  345. }
  346. vTaskDelayUntil( &vLastWakeTime, 10000 / portTICK_PERIOD_MS );
  347. }
  348. }
  349. void init_tsl2561()
  350. {
  351. xTaskCreate(&tsl2561_task, "tsl2561_task", 2048, NULL, 5, NULL);
  352. }
  353. #endif