| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375 |
- /*
- xsns_24_si1145.ino - SI1145/46/47 UV Index / IR / Visible light sensor support for Sonoff-Tasmota
- Copyright (C) 2018 Theo Arends
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
- #ifdef USE_I2C
- #ifdef USE_SI1145
- /*********************************************************************************************\
- * SI1145/46/47 - UV Index / IR / Visible light
- *
- * Based on library https://github.com/SeeedDocument/Grove-Sunlight_Sensor/
- *
- * I2C Addresses: 0x60
- \*********************************************************************************************/
- #define XSNS_24 24
- #define SI114X_ADDR 0X60
- //
- //commands
- //
- #define SI114X_QUERY 0X80
- #define SI114X_SET 0XA0
- #define SI114X_NOP 0X00
- #define SI114X_RESET 0X01
- #define SI114X_BUSADDR 0X02
- #define SI114X_PS_FORCE 0X05
- #define SI114X_GET_CAL 0X12
- #define SI114X_ALS_FORCE 0X06
- #define SI114X_PSALS_FORCE 0X07
- #define SI114X_PS_PAUSE 0X09
- #define SI114X_ALS_PAUSE 0X0A
- #define SI114X_PSALS_PAUSE 0X0B
- #define SI114X_PS_AUTO 0X0D
- #define SI114X_ALS_AUTO 0X0E
- #define SI114X_PSALS_AUTO 0X0F
- //
- //IIC REGISTERS
- //
- #define SI114X_PART_ID 0X00
- #define SI114X_REV_ID 0X01
- #define SI114X_SEQ_ID 0X02
- #define SI114X_INT_CFG 0X03
- #define SI114X_IRQ_ENABLE 0X04
- #define SI114X_IRQ_MODE1 0x05
- #define SI114X_IRQ_MODE2 0x06
- #define SI114X_HW_KEY 0X07
- #define SI114X_MEAS_RATE0 0X08
- #define SI114X_MEAS_RATE1 0X09
- #define SI114X_PS_RATE 0X0A
- #define SI114X_PS_LED21 0X0F
- #define SI114X_PS_LED3 0X10
- #define SI114X_UCOEFF0 0X13
- #define SI114X_UCOEFF1 0X14
- #define SI114X_UCOEFF2 0X15
- #define SI114X_UCOEFF3 0X16
- #define SI114X_WR 0X17
- #define SI114X_COMMAND 0X18
- #define SI114X_RESPONSE 0X20
- #define SI114X_IRQ_STATUS 0X21
- #define SI114X_ALS_VIS_DATA0 0X22
- #define SI114X_ALS_VIS_DATA1 0X23
- #define SI114X_ALS_IR_DATA0 0X24
- #define SI114X_ALS_IR_DATA1 0X25
- #define SI114X_PS1_DATA0 0X26
- #define SI114X_PS1_DATA1 0X27
- #define SI114X_PS2_DATA0 0X28
- #define SI114X_PS2_DATA1 0X29
- #define SI114X_PS3_DATA0 0X2A
- #define SI114X_PS3_DATA1 0X2B
- #define SI114X_AUX_DATA0_UVINDEX0 0X2C
- #define SI114X_AUX_DATA1_UVINDEX1 0X2D
- #define SI114X_RD 0X2E
- #define SI114X_CHIP_STAT 0X30
- //
- //Parameters
- //
- #define SI114X_CHLIST 0X01
- #define SI114X_CHLIST_ENUV 0x80
- #define SI114X_CHLIST_ENAUX 0x40
- #define SI114X_CHLIST_ENALSIR 0x20
- #define SI114X_CHLIST_ENALSVIS 0x10
- #define SI114X_CHLIST_ENPS1 0x01
- #define SI114X_CHLIST_ENPS2 0x02
- #define SI114X_CHLIST_ENPS3 0x04
- #define SI114X_PSLED12_SELECT 0X02
- #define SI114X_PSLED3_SELECT 0X03
- #define SI114X_PS_ENCODE 0X05
- #define SI114X_ALS_ENCODE 0X06
- #define SI114X_PS1_ADCMUX 0X07
- #define SI114X_PS2_ADCMUX 0X08
- #define SI114X_PS3_ADCMUX 0X09
- #define SI114X_PS_ADC_COUNTER 0X0A
- #define SI114X_PS_ADC_GAIN 0X0B
- #define SI114X_PS_ADC_MISC 0X0C
- #define SI114X_ALS_IR_ADC_MUX 0X0E
- #define SI114X_AUX_ADC_MUX 0X0F
- #define SI114X_ALS_VIS_ADC_COUNTER 0X10
- #define SI114X_ALS_VIS_ADC_GAIN 0X11
- #define SI114X_ALS_VIS_ADC_MISC 0X12
- #define SI114X_LED_REC 0X1C
- #define SI114X_ALS_IR_ADC_COUNTER 0X1D
- #define SI114X_ALS_IR_ADC_GAIN 0X1E
- #define SI114X_ALS_IR_ADC_MISC 0X1F
- //
- //USER SETTINGS DEFINE
- //
- //ADCMUX
- #define SI114X_ADCMUX_SMALL_IR 0x00
- #define SI114X_ADCMUX_VISIABLE 0x02
- #define SI114X_ADCMUX_LARGE_IR 0x03
- #define SI114X_ADCMUX_NO 0x06
- #define SI114X_ADCMUX_GND 0x25
- #define SI114X_ADCMUX_TEMPERATURE 0x65
- #define SI114X_ADCMUX_VDD 0x75
- //LED SEL
- #define SI114X_PSLED12_SELECT_PS1_NONE 0x00
- #define SI114X_PSLED12_SELECT_PS1_LED1 0x01
- #define SI114X_PSLED12_SELECT_PS1_LED2 0x02
- #define SI114X_PSLED12_SELECT_PS1_LED3 0x04
- #define SI114X_PSLED12_SELECT_PS2_NONE 0x00
- #define SI114X_PSLED12_SELECT_PS2_LED1 0x10
- #define SI114X_PSLED12_SELECT_PS2_LED2 0x20
- #define SI114X_PSLED12_SELECT_PS2_LED3 0x40
- #define SI114X_PSLED3_SELECT_PS2_NONE 0x00
- #define SI114X_PSLED3_SELECT_PS2_LED1 0x10
- #define SI114X_PSLED3_SELECT_PS2_LED2 0x20
- #define SI114X_PSLED3_SELECT_PS2_LED3 0x40
- //ADC GAIN DIV
- #define SI114X_ADC_GAIN_DIV1 0X00
- #define SI114X_ADC_GAIN_DIV2 0X01
- #define SI114X_ADC_GAIN_DIV4 0X02
- #define SI114X_ADC_GAIN_DIV8 0X03
- #define SI114X_ADC_GAIN_DIV16 0X04
- #define SI114X_ADC_GAIN_DIV32 0X05
- //LED CURRENT
- #define SI114X_LED_CURRENT_5MA 0X01
- #define SI114X_LED_CURRENT_11MA 0X02
- #define SI114X_LED_CURRENT_22MA 0X03
- #define SI114X_LED_CURRENT_45MA 0X04
- //Recovery period the ADC takes before making a PS measurement
- #define SI114X_ADC_COUNTER_1ADCCLK 0X00
- #define SI114X_ADC_COUNTER_7ADCCLK 0X01
- #define SI114X_ADC_COUNTER_15ADCCLK 0X02
- #define SI114X_ADC_COUNTER_31ADCCLK 0X03
- #define SI114X_ADC_COUNTER_63ADCCLK 0X04
- #define SI114X_ADC_COUNTER_127ADCCLK 0X05
- #define SI114X_ADC_COUNTER_255ADCCLK 0X06
- #define SI114X_ADC_COUNTER_511ADCCLK 0X07
- //ADC MISC
- #define SI114X_ADC_MISC_LOWRANGE 0X00
- #define SI114X_ADC_MISC_HIGHRANGE 0X20
- #define SI114X_ADC_MISC_ADC_NORMALPROXIMITY 0X00
- #define SI114X_ADC_MISC_ADC_RAWADC 0X04
- //INT OE
- #define SI114X_INT_CFG_INTOE 0X01
- //IRQ ENABLE
- #define SI114X_IRQEN_ALS 0x01
- #define SI114X_IRQEN_PS1 0x04
- #define SI114X_IRQEN_PS2 0x08
- #define SI114X_IRQEN_PS3 0x10
- uint8_t si1145_type = 0;
- /********************************************************************************************/
- uint8_t Si1145ReadByte(uint8_t reg)
- {
- return I2cRead8(SI114X_ADDR, reg);
- }
- uint16_t Si1145ReadHalfWord(uint8_t reg)
- {
- return I2cRead16LE(SI114X_ADDR, reg);
- }
- bool Si1145WriteByte(uint8_t reg, uint16_t val)
- {
- I2cWrite8(SI114X_ADDR, reg, val);
- }
- uint8_t Si1145WriteParamData(uint8_t p, uint8_t v)
- {
- Si1145WriteByte(SI114X_WR, v);
- Si1145WriteByte(SI114X_COMMAND, p | SI114X_SET);
- return Si1145ReadByte(SI114X_RD);
- }
- /********************************************************************************************/
- bool Si1145Present(void)
- {
- return (Si1145ReadByte(SI114X_PART_ID) == 0X45);
- }
- void Si1145Reset(void)
- {
- Si1145WriteByte(SI114X_MEAS_RATE0, 0);
- Si1145WriteByte(SI114X_MEAS_RATE1, 0);
- Si1145WriteByte(SI114X_IRQ_ENABLE, 0);
- Si1145WriteByte(SI114X_IRQ_MODE1, 0);
- Si1145WriteByte(SI114X_IRQ_MODE2, 0);
- Si1145WriteByte(SI114X_INT_CFG, 0);
- Si1145WriteByte(SI114X_IRQ_STATUS, 0xFF);
- Si1145WriteByte(SI114X_COMMAND, SI114X_RESET);
- delay(10);
- Si1145WriteByte(SI114X_HW_KEY, 0x17);
- delay(10);
- }
- void Si1145DeInit(void)
- {
- //ENABLE UV reading
- //these reg must be set to the fixed value
- Si1145WriteByte(SI114X_UCOEFF0, 0x29);
- Si1145WriteByte(SI114X_UCOEFF1, 0x89);
- Si1145WriteByte(SI114X_UCOEFF2, 0x02);
- Si1145WriteByte(SI114X_UCOEFF3, 0x00);
- Si1145WriteParamData(SI114X_CHLIST, SI114X_CHLIST_ENUV | SI114X_CHLIST_ENALSIR | SI114X_CHLIST_ENALSVIS | SI114X_CHLIST_ENPS1);
- //
- //set LED1 CURRENT(22.4mA)(It is a normal value for many LED)
- //
- Si1145WriteParamData(SI114X_PS1_ADCMUX, SI114X_ADCMUX_LARGE_IR);
- Si1145WriteByte(SI114X_PS_LED21, SI114X_LED_CURRENT_22MA);
- Si1145WriteParamData(SI114X_PSLED12_SELECT, SI114X_PSLED12_SELECT_PS1_LED1);
- //
- //PS ADC SETTING
- //
- Si1145WriteParamData(SI114X_PS_ADC_GAIN, SI114X_ADC_GAIN_DIV1);
- Si1145WriteParamData(SI114X_PS_ADC_COUNTER, SI114X_ADC_COUNTER_511ADCCLK);
- Si1145WriteParamData(SI114X_PS_ADC_MISC, SI114X_ADC_MISC_HIGHRANGE | SI114X_ADC_MISC_ADC_RAWADC);
- //
- //VIS ADC SETTING
- //
- Si1145WriteParamData(SI114X_ALS_VIS_ADC_GAIN, SI114X_ADC_GAIN_DIV1);
- Si1145WriteParamData(SI114X_ALS_VIS_ADC_COUNTER, SI114X_ADC_COUNTER_511ADCCLK);
- Si1145WriteParamData(SI114X_ALS_VIS_ADC_MISC, SI114X_ADC_MISC_HIGHRANGE);
- //
- //IR ADC SETTING
- //
- Si1145WriteParamData(SI114X_ALS_IR_ADC_GAIN, SI114X_ADC_GAIN_DIV1);
- Si1145WriteParamData(SI114X_ALS_IR_ADC_COUNTER, SI114X_ADC_COUNTER_511ADCCLK);
- Si1145WriteParamData(SI114X_ALS_IR_ADC_MISC, SI114X_ADC_MISC_HIGHRANGE);
- //
- //interrupt enable
- //
- Si1145WriteByte(SI114X_INT_CFG, SI114X_INT_CFG_INTOE);
- Si1145WriteByte(SI114X_IRQ_ENABLE, SI114X_IRQEN_ALS);
- //
- //AUTO RUN
- //
- Si1145WriteByte(SI114X_MEAS_RATE0, 0xFF);
- Si1145WriteByte(SI114X_COMMAND, SI114X_PSALS_AUTO);
- }
- boolean Si1145Begin(void)
- {
- if (!Si1145Present()) { return false; }
- Si1145Reset();
- Si1145DeInit();
- return true;
- }
- // returns the UV index * 100 (divide by 100 to get the index)
- uint16_t Si1145ReadUV(void)
- {
- return Si1145ReadHalfWord(SI114X_AUX_DATA0_UVINDEX0);
- }
- // returns visible+IR light levels
- uint16_t Si1145ReadVisible(void)
- {
- return Si1145ReadHalfWord(SI114X_ALS_VIS_DATA0);
- }
- // returns IR light levels
- uint16_t Si1145ReadIR(void)
- {
- return Si1145ReadHalfWord(SI114X_ALS_IR_DATA0);
- }
- /********************************************************************************************/
- void Si1145Update(void)
- {
- if (!si1145_type) {
- if (Si1145Begin()) {
- si1145_type = 1;
- snprintf_P(log_data, sizeof(log_data), S_LOG_I2C_FOUND_AT, "SI1145", SI114X_ADDR);
- AddLog(LOG_LEVEL_DEBUG);
- }
- }
- }
- #ifdef USE_WEBSERVER
- const char HTTP_SNS_SI1145[] PROGMEM = "%s"
- "{s}SI1145 " D_ILLUMINANCE "{m}%d " D_UNIT_LUX "{e}" // {s} = <tr><th>, {m} = </th><td>, {e} = </td></tr>
- "{s}SI1145 " D_INFRARED "{m}%d " D_UNIT_LUX "{e}"
- "{s}SI1145 " D_UV_INDEX "{m}%d.%d{e}";
- #endif // USE_WEBSERVER
- void Si1145Show(boolean json)
- {
- if (si1145_type && Si1145Present()) {
- uint16_t visible = Si1145ReadVisible();
- uint16_t infrared = Si1145ReadIR();
- uint16_t uvindex = Si1145ReadUV();
- if (json) {
- snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"SI1145\":{\"" D_JSON_ILLUMINANCE "\":%d,\"" D_JSON_INFRARED "\":%d,\"" D_JSON_UVINDEX "\":%d.%d}"),
- mqtt_data, visible, infrared, uvindex /100, uvindex %100);
- #ifdef USE_DOMOTICZ
- if (0 == tele_period) DomoticzSensor(DZ_ILLUMINANCE, visible);
- #endif // USE_DOMOTICZ
- #ifdef USE_WEBSERVER
- } else {
- snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_SI1145, mqtt_data, visible, infrared, uvindex /100, uvindex %100);
- #endif
- }
- } else {
- si1145_type = 0;
- }
- }
- /*********************************************************************************************\
- * Interface
- \*********************************************************************************************/
- boolean Xsns24(byte function)
- {
- boolean result = false;
- if (i2c_flg) {
- switch (function) {
- case FUNC_EVERY_SECOND:
- Si1145Update();
- break;
- case FUNC_JSON_APPEND:
- Si1145Show(1);
- break;
- #ifdef USE_WEBSERVER
- case FUNC_WEB_APPEND:
- Si1145Show(0);
- break;
- #endif // USE_WEBSERVER
- }
- }
- return result;
- }
- #endif // USE_SI1145
- #endif // USE_I2C
|