xsns_24_si1145.ino 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375
  1. /*
  2. xsns_24_si1145.ino - SI1145/46/47 UV Index / IR / Visible light sensor support for Sonoff-Tasmota
  3. Copyright (C) 2018 Theo Arends
  4. This program is free software: you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation, either version 3 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program. If not, see <http://www.gnu.org/licenses/>.
  14. */
  15. #ifdef USE_I2C
  16. #ifdef USE_SI1145
  17. /*********************************************************************************************\
  18. * SI1145/46/47 - UV Index / IR / Visible light
  19. *
  20. * Based on library https://github.com/SeeedDocument/Grove-Sunlight_Sensor/
  21. *
  22. * I2C Addresses: 0x60
  23. \*********************************************************************************************/
  24. #define XSNS_24 24
  25. #define SI114X_ADDR 0X60
  26. //
  27. //commands
  28. //
  29. #define SI114X_QUERY 0X80
  30. #define SI114X_SET 0XA0
  31. #define SI114X_NOP 0X00
  32. #define SI114X_RESET 0X01
  33. #define SI114X_BUSADDR 0X02
  34. #define SI114X_PS_FORCE 0X05
  35. #define SI114X_GET_CAL 0X12
  36. #define SI114X_ALS_FORCE 0X06
  37. #define SI114X_PSALS_FORCE 0X07
  38. #define SI114X_PS_PAUSE 0X09
  39. #define SI114X_ALS_PAUSE 0X0A
  40. #define SI114X_PSALS_PAUSE 0X0B
  41. #define SI114X_PS_AUTO 0X0D
  42. #define SI114X_ALS_AUTO 0X0E
  43. #define SI114X_PSALS_AUTO 0X0F
  44. //
  45. //IIC REGISTERS
  46. //
  47. #define SI114X_PART_ID 0X00
  48. #define SI114X_REV_ID 0X01
  49. #define SI114X_SEQ_ID 0X02
  50. #define SI114X_INT_CFG 0X03
  51. #define SI114X_IRQ_ENABLE 0X04
  52. #define SI114X_IRQ_MODE1 0x05
  53. #define SI114X_IRQ_MODE2 0x06
  54. #define SI114X_HW_KEY 0X07
  55. #define SI114X_MEAS_RATE0 0X08
  56. #define SI114X_MEAS_RATE1 0X09
  57. #define SI114X_PS_RATE 0X0A
  58. #define SI114X_PS_LED21 0X0F
  59. #define SI114X_PS_LED3 0X10
  60. #define SI114X_UCOEFF0 0X13
  61. #define SI114X_UCOEFF1 0X14
  62. #define SI114X_UCOEFF2 0X15
  63. #define SI114X_UCOEFF3 0X16
  64. #define SI114X_WR 0X17
  65. #define SI114X_COMMAND 0X18
  66. #define SI114X_RESPONSE 0X20
  67. #define SI114X_IRQ_STATUS 0X21
  68. #define SI114X_ALS_VIS_DATA0 0X22
  69. #define SI114X_ALS_VIS_DATA1 0X23
  70. #define SI114X_ALS_IR_DATA0 0X24
  71. #define SI114X_ALS_IR_DATA1 0X25
  72. #define SI114X_PS1_DATA0 0X26
  73. #define SI114X_PS1_DATA1 0X27
  74. #define SI114X_PS2_DATA0 0X28
  75. #define SI114X_PS2_DATA1 0X29
  76. #define SI114X_PS3_DATA0 0X2A
  77. #define SI114X_PS3_DATA1 0X2B
  78. #define SI114X_AUX_DATA0_UVINDEX0 0X2C
  79. #define SI114X_AUX_DATA1_UVINDEX1 0X2D
  80. #define SI114X_RD 0X2E
  81. #define SI114X_CHIP_STAT 0X30
  82. //
  83. //Parameters
  84. //
  85. #define SI114X_CHLIST 0X01
  86. #define SI114X_CHLIST_ENUV 0x80
  87. #define SI114X_CHLIST_ENAUX 0x40
  88. #define SI114X_CHLIST_ENALSIR 0x20
  89. #define SI114X_CHLIST_ENALSVIS 0x10
  90. #define SI114X_CHLIST_ENPS1 0x01
  91. #define SI114X_CHLIST_ENPS2 0x02
  92. #define SI114X_CHLIST_ENPS3 0x04
  93. #define SI114X_PSLED12_SELECT 0X02
  94. #define SI114X_PSLED3_SELECT 0X03
  95. #define SI114X_PS_ENCODE 0X05
  96. #define SI114X_ALS_ENCODE 0X06
  97. #define SI114X_PS1_ADCMUX 0X07
  98. #define SI114X_PS2_ADCMUX 0X08
  99. #define SI114X_PS3_ADCMUX 0X09
  100. #define SI114X_PS_ADC_COUNTER 0X0A
  101. #define SI114X_PS_ADC_GAIN 0X0B
  102. #define SI114X_PS_ADC_MISC 0X0C
  103. #define SI114X_ALS_IR_ADC_MUX 0X0E
  104. #define SI114X_AUX_ADC_MUX 0X0F
  105. #define SI114X_ALS_VIS_ADC_COUNTER 0X10
  106. #define SI114X_ALS_VIS_ADC_GAIN 0X11
  107. #define SI114X_ALS_VIS_ADC_MISC 0X12
  108. #define SI114X_LED_REC 0X1C
  109. #define SI114X_ALS_IR_ADC_COUNTER 0X1D
  110. #define SI114X_ALS_IR_ADC_GAIN 0X1E
  111. #define SI114X_ALS_IR_ADC_MISC 0X1F
  112. //
  113. //USER SETTINGS DEFINE
  114. //
  115. //ADCMUX
  116. #define SI114X_ADCMUX_SMALL_IR 0x00
  117. #define SI114X_ADCMUX_VISIABLE 0x02
  118. #define SI114X_ADCMUX_LARGE_IR 0x03
  119. #define SI114X_ADCMUX_NO 0x06
  120. #define SI114X_ADCMUX_GND 0x25
  121. #define SI114X_ADCMUX_TEMPERATURE 0x65
  122. #define SI114X_ADCMUX_VDD 0x75
  123. //LED SEL
  124. #define SI114X_PSLED12_SELECT_PS1_NONE 0x00
  125. #define SI114X_PSLED12_SELECT_PS1_LED1 0x01
  126. #define SI114X_PSLED12_SELECT_PS1_LED2 0x02
  127. #define SI114X_PSLED12_SELECT_PS1_LED3 0x04
  128. #define SI114X_PSLED12_SELECT_PS2_NONE 0x00
  129. #define SI114X_PSLED12_SELECT_PS2_LED1 0x10
  130. #define SI114X_PSLED12_SELECT_PS2_LED2 0x20
  131. #define SI114X_PSLED12_SELECT_PS2_LED3 0x40
  132. #define SI114X_PSLED3_SELECT_PS2_NONE 0x00
  133. #define SI114X_PSLED3_SELECT_PS2_LED1 0x10
  134. #define SI114X_PSLED3_SELECT_PS2_LED2 0x20
  135. #define SI114X_PSLED3_SELECT_PS2_LED3 0x40
  136. //ADC GAIN DIV
  137. #define SI114X_ADC_GAIN_DIV1 0X00
  138. #define SI114X_ADC_GAIN_DIV2 0X01
  139. #define SI114X_ADC_GAIN_DIV4 0X02
  140. #define SI114X_ADC_GAIN_DIV8 0X03
  141. #define SI114X_ADC_GAIN_DIV16 0X04
  142. #define SI114X_ADC_GAIN_DIV32 0X05
  143. //LED CURRENT
  144. #define SI114X_LED_CURRENT_5MA 0X01
  145. #define SI114X_LED_CURRENT_11MA 0X02
  146. #define SI114X_LED_CURRENT_22MA 0X03
  147. #define SI114X_LED_CURRENT_45MA 0X04
  148. //Recovery period the ADC takes before making a PS measurement
  149. #define SI114X_ADC_COUNTER_1ADCCLK 0X00
  150. #define SI114X_ADC_COUNTER_7ADCCLK 0X01
  151. #define SI114X_ADC_COUNTER_15ADCCLK 0X02
  152. #define SI114X_ADC_COUNTER_31ADCCLK 0X03
  153. #define SI114X_ADC_COUNTER_63ADCCLK 0X04
  154. #define SI114X_ADC_COUNTER_127ADCCLK 0X05
  155. #define SI114X_ADC_COUNTER_255ADCCLK 0X06
  156. #define SI114X_ADC_COUNTER_511ADCCLK 0X07
  157. //ADC MISC
  158. #define SI114X_ADC_MISC_LOWRANGE 0X00
  159. #define SI114X_ADC_MISC_HIGHRANGE 0X20
  160. #define SI114X_ADC_MISC_ADC_NORMALPROXIMITY 0X00
  161. #define SI114X_ADC_MISC_ADC_RAWADC 0X04
  162. //INT OE
  163. #define SI114X_INT_CFG_INTOE 0X01
  164. //IRQ ENABLE
  165. #define SI114X_IRQEN_ALS 0x01
  166. #define SI114X_IRQEN_PS1 0x04
  167. #define SI114X_IRQEN_PS2 0x08
  168. #define SI114X_IRQEN_PS3 0x10
  169. uint8_t si1145_type = 0;
  170. /********************************************************************************************/
  171. uint8_t Si1145ReadByte(uint8_t reg)
  172. {
  173. return I2cRead8(SI114X_ADDR, reg);
  174. }
  175. uint16_t Si1145ReadHalfWord(uint8_t reg)
  176. {
  177. return I2cRead16LE(SI114X_ADDR, reg);
  178. }
  179. bool Si1145WriteByte(uint8_t reg, uint16_t val)
  180. {
  181. I2cWrite8(SI114X_ADDR, reg, val);
  182. }
  183. uint8_t Si1145WriteParamData(uint8_t p, uint8_t v)
  184. {
  185. Si1145WriteByte(SI114X_WR, v);
  186. Si1145WriteByte(SI114X_COMMAND, p | SI114X_SET);
  187. return Si1145ReadByte(SI114X_RD);
  188. }
  189. /********************************************************************************************/
  190. bool Si1145Present(void)
  191. {
  192. return (Si1145ReadByte(SI114X_PART_ID) == 0X45);
  193. }
  194. void Si1145Reset(void)
  195. {
  196. Si1145WriteByte(SI114X_MEAS_RATE0, 0);
  197. Si1145WriteByte(SI114X_MEAS_RATE1, 0);
  198. Si1145WriteByte(SI114X_IRQ_ENABLE, 0);
  199. Si1145WriteByte(SI114X_IRQ_MODE1, 0);
  200. Si1145WriteByte(SI114X_IRQ_MODE2, 0);
  201. Si1145WriteByte(SI114X_INT_CFG, 0);
  202. Si1145WriteByte(SI114X_IRQ_STATUS, 0xFF);
  203. Si1145WriteByte(SI114X_COMMAND, SI114X_RESET);
  204. delay(10);
  205. Si1145WriteByte(SI114X_HW_KEY, 0x17);
  206. delay(10);
  207. }
  208. void Si1145DeInit(void)
  209. {
  210. //ENABLE UV reading
  211. //these reg must be set to the fixed value
  212. Si1145WriteByte(SI114X_UCOEFF0, 0x29);
  213. Si1145WriteByte(SI114X_UCOEFF1, 0x89);
  214. Si1145WriteByte(SI114X_UCOEFF2, 0x02);
  215. Si1145WriteByte(SI114X_UCOEFF3, 0x00);
  216. Si1145WriteParamData(SI114X_CHLIST, SI114X_CHLIST_ENUV | SI114X_CHLIST_ENALSIR | SI114X_CHLIST_ENALSVIS | SI114X_CHLIST_ENPS1);
  217. //
  218. //set LED1 CURRENT(22.4mA)(It is a normal value for many LED)
  219. //
  220. Si1145WriteParamData(SI114X_PS1_ADCMUX, SI114X_ADCMUX_LARGE_IR);
  221. Si1145WriteByte(SI114X_PS_LED21, SI114X_LED_CURRENT_22MA);
  222. Si1145WriteParamData(SI114X_PSLED12_SELECT, SI114X_PSLED12_SELECT_PS1_LED1);
  223. //
  224. //PS ADC SETTING
  225. //
  226. Si1145WriteParamData(SI114X_PS_ADC_GAIN, SI114X_ADC_GAIN_DIV1);
  227. Si1145WriteParamData(SI114X_PS_ADC_COUNTER, SI114X_ADC_COUNTER_511ADCCLK);
  228. Si1145WriteParamData(SI114X_PS_ADC_MISC, SI114X_ADC_MISC_HIGHRANGE | SI114X_ADC_MISC_ADC_RAWADC);
  229. //
  230. //VIS ADC SETTING
  231. //
  232. Si1145WriteParamData(SI114X_ALS_VIS_ADC_GAIN, SI114X_ADC_GAIN_DIV1);
  233. Si1145WriteParamData(SI114X_ALS_VIS_ADC_COUNTER, SI114X_ADC_COUNTER_511ADCCLK);
  234. Si1145WriteParamData(SI114X_ALS_VIS_ADC_MISC, SI114X_ADC_MISC_HIGHRANGE);
  235. //
  236. //IR ADC SETTING
  237. //
  238. Si1145WriteParamData(SI114X_ALS_IR_ADC_GAIN, SI114X_ADC_GAIN_DIV1);
  239. Si1145WriteParamData(SI114X_ALS_IR_ADC_COUNTER, SI114X_ADC_COUNTER_511ADCCLK);
  240. Si1145WriteParamData(SI114X_ALS_IR_ADC_MISC, SI114X_ADC_MISC_HIGHRANGE);
  241. //
  242. //interrupt enable
  243. //
  244. Si1145WriteByte(SI114X_INT_CFG, SI114X_INT_CFG_INTOE);
  245. Si1145WriteByte(SI114X_IRQ_ENABLE, SI114X_IRQEN_ALS);
  246. //
  247. //AUTO RUN
  248. //
  249. Si1145WriteByte(SI114X_MEAS_RATE0, 0xFF);
  250. Si1145WriteByte(SI114X_COMMAND, SI114X_PSALS_AUTO);
  251. }
  252. boolean Si1145Begin(void)
  253. {
  254. if (!Si1145Present()) { return false; }
  255. Si1145Reset();
  256. Si1145DeInit();
  257. return true;
  258. }
  259. // returns the UV index * 100 (divide by 100 to get the index)
  260. uint16_t Si1145ReadUV(void)
  261. {
  262. return Si1145ReadHalfWord(SI114X_AUX_DATA0_UVINDEX0);
  263. }
  264. // returns visible+IR light levels
  265. uint16_t Si1145ReadVisible(void)
  266. {
  267. return Si1145ReadHalfWord(SI114X_ALS_VIS_DATA0);
  268. }
  269. // returns IR light levels
  270. uint16_t Si1145ReadIR(void)
  271. {
  272. return Si1145ReadHalfWord(SI114X_ALS_IR_DATA0);
  273. }
  274. /********************************************************************************************/
  275. void Si1145Update(void)
  276. {
  277. if (!si1145_type) {
  278. if (Si1145Begin()) {
  279. si1145_type = 1;
  280. snprintf_P(log_data, sizeof(log_data), S_LOG_I2C_FOUND_AT, "SI1145", SI114X_ADDR);
  281. AddLog(LOG_LEVEL_DEBUG);
  282. }
  283. }
  284. }
  285. #ifdef USE_WEBSERVER
  286. const char HTTP_SNS_SI1145[] PROGMEM = "%s"
  287. "{s}SI1145 " D_ILLUMINANCE "{m}%d " D_UNIT_LUX "{e}" // {s} = <tr><th>, {m} = </th><td>, {e} = </td></tr>
  288. "{s}SI1145 " D_INFRARED "{m}%d " D_UNIT_LUX "{e}"
  289. "{s}SI1145 " D_UV_INDEX "{m}%d.%d{e}";
  290. #endif // USE_WEBSERVER
  291. void Si1145Show(boolean json)
  292. {
  293. if (si1145_type && Si1145Present()) {
  294. uint16_t visible = Si1145ReadVisible();
  295. uint16_t infrared = Si1145ReadIR();
  296. uint16_t uvindex = Si1145ReadUV();
  297. if (json) {
  298. snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"SI1145\":{\"" D_JSON_ILLUMINANCE "\":%d,\"" D_JSON_INFRARED "\":%d,\"" D_JSON_UVINDEX "\":%d.%d}"),
  299. mqtt_data, visible, infrared, uvindex /100, uvindex %100);
  300. #ifdef USE_DOMOTICZ
  301. if (0 == tele_period) DomoticzSensor(DZ_ILLUMINANCE, visible);
  302. #endif // USE_DOMOTICZ
  303. #ifdef USE_WEBSERVER
  304. } else {
  305. snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_SI1145, mqtt_data, visible, infrared, uvindex /100, uvindex %100);
  306. #endif
  307. }
  308. } else {
  309. si1145_type = 0;
  310. }
  311. }
  312. /*********************************************************************************************\
  313. * Interface
  314. \*********************************************************************************************/
  315. boolean Xsns24(byte function)
  316. {
  317. boolean result = false;
  318. if (i2c_flg) {
  319. switch (function) {
  320. case FUNC_EVERY_SECOND:
  321. Si1145Update();
  322. break;
  323. case FUNC_JSON_APPEND:
  324. Si1145Show(1);
  325. break;
  326. #ifdef USE_WEBSERVER
  327. case FUNC_WEB_APPEND:
  328. Si1145Show(0);
  329. break;
  330. #endif // USE_WEBSERVER
  331. }
  332. }
  333. return result;
  334. }
  335. #endif // USE_SI1145
  336. #endif // USE_I2C