diff --git a/I2CDEVICES.md b/I2CDEVICES.md index 07094954b..65b38dae9 100644 --- a/I2CDEVICES.md +++ b/I2CDEVICES.md @@ -97,3 +97,4 @@ Index | Define | Driver | Device | Address(es) | Description 61 | USE_T67XX | xsns_89 | T67XX | 0x15 | CO2 sensor 62 | USE_SCD40 | xsns_92 | SCD40 | 0x62 | CO2 sensor Sensirion SCD40/SCD41 63 | USE_HM330X | xsns_93 | HM330X | 0x40 | Particule sensor + 64 | USE_HDC2010 | xsns_94 | HDC2010 | 0x40 | Temperature and Humidity sensor diff --git a/tasmota/my_user_config.h b/tasmota/my_user_config.h index 2640d3de5..6f708f58b 100644 --- a/tasmota/my_user_config.h +++ b/tasmota/my_user_config.h @@ -658,6 +658,7 @@ // #define USE_AM2320 // [I2cDriver60] Enable AM2320 temperature and humidity Sensor (I2C address 0x5C) (+1k code) // #define USE_T67XX // [I2cDriver61] Enable Telaire T67XX CO2 sensor (I2C address 0x15) (+1k3 code) // #define USE_HM330X // [I2cDriver63] Enable support for SeedStudio Grove Particule sensor (I2C address 0x40) (+1k5 code) +// #define USE_HDC2010 // [I2cDriver64] Enable HDC2010 temperature/humidity sensor (I2C address 0x40) (+1k5 code) // #define HM330X_DEFAULT_ADDRESS 0x40 // Option: change default I2C address for HM330X used in SeedSTudio Particucle Sensor // #define HM330X_WARMUP_DELAY 30 // Option: change warmup delay during which data are not read from sensor after a power up // #define HM330X_HIDE_OUT_OF_DATE false // Option: change to true to hide data from web GUI and SENSOR while sensor is asleep diff --git a/tasmota/tasmota_configurations.h b/tasmota/tasmota_configurations.h index 59810fccd..f2fe27392 100644 --- a/tasmota/tasmota_configurations.h +++ b/tasmota/tasmota_configurations.h @@ -148,6 +148,7 @@ //#define USE_BM8563 // [I2cDriver59] Enable BM8563 RTC - found in M5Stack - support both I2C buses on ESP32 (I2C address 0x51) (+2k5 code) //#define USE_AM2320 // [I2cDriver60] Enable AM2320 temperature and humidity Sensor (I2C address 0x5C) (+1k code) //#define USE_T67XX // [I2cDriver61] Enable Telaire T67XX CO2 sensor (I2C address 0x15) (+1k3 code) +//#define USE_HDC2010 // [I2cDriver64] Enable HDC2010 temperature/humidity sensor (I2C address 0x40) (+1k5 code) //#define USE_SPI // Hardware SPI using GPIO12(MISO), GPIO13(MOSI) and GPIO14(CLK) in addition to two user selectable GPIOs(CS and DC) //#define USE_RC522 // Add support for MFRC522 13.56Mhz Rfid reader (+6k code) diff --git a/tasmota/xsns_94_hdc2010.ino b/tasmota/xsns_94_hdc2010.ino new file mode 100755 index 000000000..edacc2adf --- /dev/null +++ b/tasmota/xsns_94_hdc2010.ino @@ -0,0 +1,215 @@ +/* + xsns_94_hdc2010.ino - Texas Instruments HDC1080 temperature and humidity sensor support for Tasmota + + Copyright (C) 2021 Luc Boudreau + + 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 . +*/ + +#ifdef USE_I2C +#ifdef USE_HDC2010 + +/*********************************************************************************************\ + * HDC2010 - Temperature and Humidity sensor + * + * Source: Luc Boudreau + * Other sources: Luis Teixeira from the HDC1080 code (GPL3+) + * sSense arduino library (Public Domain) + * + * I2C Address: 0x40 +\*********************************************************************************************/ + +#define XSNS_94 94 +#define XI2C_64 64 // See I2CDEVICES.md + +#define HDC2010_ADDR 0x40 + +// Registers: + +#define HDC2010_REG_TEMP_LSB 0x00 // Temperature register LSB +#define HDC2010_REG_TEMP_MSB 0x01 // Temperature register MSB +#define HDC2010_REG_RH_LSB 0x02 // Humidity register LSB +#define HDC2010_REG_RH_MSB 0x03 // Humidity register MSB +#define HDC2010_REG_INTR_DRDY 0x04 // Interrupt / Data Ready register +#define HDC2010_REG_CONFIG 0x0F // Configuration register +#define HDC2010_REG_RESET 0x0E // Reset register +#define HDC2010_REG_MAN_LSB 0xFC // Manufacturer LSB +#define HDC2010_REG_MAN_MSB 0xFD // Manufacturer MSB +#define HDC2010_REG_DEV_LSB 0xFE // Device ID LSB +#define HDC2010_REG_DEV_MSB 0xFF // Device ID MSB + +// Note: These are bit flipped. Actual IDs need to shift byte 0 and 1 +#define HDC2010_MAN_ID 0x4954 // Manufacturer ID (Texas Instruments) +#define HDC2010_DEV_ID 0xD007 // Device ID (valid for the HDC2010) + +#define HDC2010_CONV_TIME 50 + +struct HDC2010 { + const char* hdc_type_name = "HDC2010"; + uint16_t hdc_manufacturer_id = 0; + uint16_t hdc_device_id = 0; + float hdc_temperature = 0.0; + float hdc_humidity = 0.0; + uint8_t hdc_valid = 0; +} HDC2010; + +/** + * Reads the device ID register. + */ +uint16_t Hdc2010ReadDeviceId(void) { + return I2cRead16(HDC2010_ADDR, HDC2010_REG_DEV_LSB); +} + +/** + * Reads the manufacturer ID register. + */ +uint16_t Hdc2010ReadManufacturerId(void) { + return I2cRead16(HDC2010_ADDR, HDC2010_REG_MAN_LSB); +} + +/** + * The various initialization steps for this sensor. + */ +void Hdc2010Init(void) { + Hdc2010Reset(); + Hdc2010SetMeasurementConfig(); + HDC2010.hdc_valid = 1; +} + +/** + * Performs a temp and humidity read + */ +void Hdc2010Read(void) { + uint8_t byte[2]; + uint16_t temp; + uint16_t humidity; + byte[0] = I2cRead8(HDC2010_ADDR, HDC2010_REG_TEMP_LSB); + byte[1] = I2cRead8(HDC2010_ADDR, HDC2010_REG_TEMP_MSB); + //AddLog(LOG_LEVEL_DEBUG, PSTR("HdcRead: temperature raw data: 0x%02x 0x%02x"), byte[0], byte[1]); + temp = (unsigned int)(byte[1]) << 8 | (unsigned int) byte[0]; + //AddLog(LOG_LEVEL_DEBUG, PSTR("HdcRead: temperature shifted data: %d"), temp); + HDC2010.hdc_temperature = (float)(temp) * 165 / 65536 - 40; + //AddLog(LOG_LEVEL_DEBUG, PSTR("HdcRead: temperature : %f"), hdc_temperature); + + byte[0] = I2cRead8(HDC2010_ADDR, HDC2010_REG_RH_LSB); + byte[1] = I2cRead8(HDC2010_ADDR, HDC2010_REG_RH_MSB); + //AddLog(LOG_LEVEL_DEBUG, PSTR("HdcRead: humidity raw data: 0x%02x 0x%02x"), byte[0], byte[1]); + humidity = (unsigned int)byte[1] << 8 | byte[0]; + //AddLog(LOG_LEVEL_DEBUG, PSTR("HdcRead: humidity shifted data: %d"), humidity); + HDC2010.hdc_humidity = (float)(humidity)/( 65536 )* 100; + //AddLog(LOG_LEVEL_DEBUG, PSTR("HdcRead: humidity : %f"), hdc_humidity); +} + +/** + * Performs a reset of the sensor (slow oper) + */ +void Hdc2010Reset(void) { + uint8_t current = I2cRead8(HDC2010_ADDR, HDC2010_REG_RESET); + //AddLog(LOG_LEVEL_DEBUG, PSTR("HdcReset: current reset registry value = %d"), current); + current |= 0x80; + //AddLog(LOG_LEVEL_DEBUG, PSTR("HdcReset: new reset registry value = %d"), current); + I2cWrite8(HDC2010_ADDR, HDC2010_REG_RESET, current); + delay(HDC2010_CONV_TIME); +} + +/** + * Detects the sensor + */ +bool Hdc2010Detect(void) { + if (!I2cSetDevice(HDC2010_ADDR)) { return false; } + + HDC2010.hdc_manufacturer_id = Hdc2010ReadManufacturerId(); + HDC2010.hdc_device_id = Hdc2010ReadDeviceId(); + + AddLog(LOG_LEVEL_DEBUG, PSTR("HdcDetect: detected device with manufacturerId = 0x%04X and deviceId = 0x%04X"), HDC2010.hdc_manufacturer_id, HDC2010.hdc_device_id); + + if (HDC2010.hdc_device_id == HDC2010_DEV_ID && HDC2010.hdc_manufacturer_id == HDC2010_MAN_ID) { + //AddLog(LOG_LEVEL_DEBUG, PSTR("HdcDetect: adding device HDC2010")); + Hdc2010Init(); + I2cSetActiveFound(HDC2010_ADDR, HDC2010.hdc_type_name); + return true; + } + return false; +} + +/** + * Shows the sensor in the ui + */ +void Hdc2010Show(bool json) { + if (HDC2010.hdc_valid) { + TempHumDewShow(json, (0 == TasmotaGlobal.tele_period), HDC2010.hdc_type_name, HDC2010.hdc_temperature, HDC2010.hdc_humidity); + } +} + +/** + * Configures measurement settings + */ +void Hdc2010SetMeasurementConfig() { + uint8_t resetContents = I2cRead8(HDC2010_ADDR, HDC2010_REG_RESET); + //AddLog(LOG_LEVEL_DEBUG, PSTR("HdcSetMeasureRate: current reset registry value = %d"), resetContents); + // Measure twice per second + resetContents |= 0x60; + //AddLog(LOG_LEVEL_DEBUG, PSTR("HdcSetMeasureRate: new reset registry value = %d"), resetContents); + I2cWrite8(HDC2010_ADDR, HDC2010_REG_RESET, resetContents); + + uint8_t configContents = I2cRead8(HDC2010_ADDR, HDC2010_REG_CONFIG); + //AddLog(LOG_LEVEL_DEBUG, PSTR("HdcSetMeasureRate: current config registry value = %d"), configContents); + // Measure both temp and humidity + configContents |= 0x01; + //AddLog(LOG_LEVEL_DEBUG, PSTR("HdcSetMeasureRate: new config registry value = %d"), configContents); + I2cWrite8(HDC2010_ADDR, HDC2010_REG_CONFIG, configContents); +} + +/*********************************************************************************************\ + * Interface +\*********************************************************************************************/ + +bool Xsns94(uint8_t function) +{ + if (!I2cEnabled(XI2C_64)) { + return false; + } + + bool result = false; + + if (FUNC_INIT == function) { + result = Hdc2010Detect(); + } + else if (HDC2010.hdc_device_id) { + switch (function) { + case FUNC_EVERY_SECOND: + if (HDC2010.hdc_valid) { + Hdc2010Read(); + result = true; + } + break; + case FUNC_JSON_APPEND: + if (HDC2010.hdc_valid) { + Hdc2010Show(1); + } + break; +#ifdef USE_WEBSERVER + case FUNC_WEB_SENSOR: + Hdc2010Show(0); + result = true; + break; +#endif // USE_WEBSERVER + } + } + return result; +} + +#endif // USE_HDC2010 +#endif // USE_I2C +