diff --git a/I2CDEVICES.md b/I2CDEVICES.md index c7b42108f..b607b3241 100644 --- a/I2CDEVICES.md +++ b/I2CDEVICES.md @@ -64,4 +64,4 @@ Index | Define | Driver | Device | Address(es) | Description 41 | USE_DHT12 | xsns_58 | DHT12 | 0x5C | Temperature and humidity sensor 42 | USE_DS1624 | xsns_59 | DS1621 | 0x48 - 0x4F | Temperature sensor 42 | USE_DS1624 | xsns_59 | DS1624 | 0x48 - 0x4F | Temperature sensor - + 43 | USE_AHT1x | xsns_63 | AHT10/15 | 0x38 | Temperature and humidity sensor diff --git a/RELEASENOTES.md b/RELEASENOTES.md index c22a4c59d..dba7abeed 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -103,3 +103,4 @@ The following binary downloads have been compiled with ESP8266/Arduino library c - Add support for FiF LE-01MR energy meter by saper-2 (#7584) - Add new DHT driver. The old driver can still be used using define USE_DHT_OLD (#7468) - Add another new DHT driver based on ESPEasy. The old driver can still be used using define USE_DHT_OLD. The previous new driver can be used with define USE_DHT_V2 (#7717) +- Add initial support for Sensors AHT10 and AHT15 by Martin Wagner (#7596) \ No newline at end of file diff --git a/tasmota/my_user_config.h b/tasmota/my_user_config.h index 67ab1cf1c..d641ac761 100644 --- a/tasmota/my_user_config.h +++ b/tasmota/my_user_config.h @@ -486,6 +486,7 @@ // #define USE_HIH6 // [I2cDriver36] Enable Honeywell HIH Humidity and Temperature sensor (I2C address 0x27) (+0k6) // #define USE_DHT12 // [I2cDriver41] Enable DHT12 humidity and temperature sensor (I2C address 0x5C) (+0k7 code) // #define USE_DS1624 // [I2cDriver42] Enable DS1624, DS1621 temperature sensor (I2C addresses 0x48 - 0x4F) (+1k2 code) +// #define USE_AHT1x // [I2cDriver43] Enable AHT10/15 humidity and temperature sensor (I2C address 0x38) (+0k8 code) // #define USE_DISPLAY // Add I2C Display Support (+2k code) #define USE_DISPLAY_MODES1TO5 // Enable display mode 1 to 5 in addition to mode 0 diff --git a/tasmota/support_features.ino b/tasmota/support_features.ino index 2dc25b8e5..85f5a77ea 100644 --- a/tasmota/support_features.ino +++ b/tasmota/support_features.ino @@ -513,8 +513,9 @@ void GetFeatures(void) #ifdef USE_LE01MR feature5 |= 0x08000000; // xnrg_13_fif_le01mr.ino #endif - -// feature5 |= 0x10000000; +#ifdef USE_AHT1x + feature5 |= 0x10000000; // xsns_63_aht1x.ino +#endif // feature5 |= 0x20000000; // feature5 |= 0x40000000; // feature5 |= 0x80000000; diff --git a/tasmota/xsns_63_aht1x.ino b/tasmota/xsns_63_aht1x.ino new file mode 100644 index 000000000..b3b17e0e4 --- /dev/null +++ b/tasmota/xsns_63_aht1x.ino @@ -0,0 +1,192 @@ +/* + xsns_63_AHT1x.ino - AHT10 I2C temperature and humidity sensor support for Tasmota + + Copyright (C) 2020 Martin Wagner + + 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_AHT1x +/*********************************************************************************************\ + * AHT10/15 - Temperature and Humidity + * + * I2C Address: 0x38 +\*********************************************************************************************/ + +#define XSNS_63 63 +#define XI2C_43 43 // See I2CDEVICES.md + +#define AHT10_ADDR 0x38 + +unsigned char eSensorCalibrateCmd[3] = {0xE1, 0x08, 0x00}; +unsigned char eSensorNormalCmd[3] = {0xA8, 0x00, 0x00}; +unsigned char eSensorMeasureCmd[3] = {0xAC, 0x33, 0x00}; +unsigned char eSensorResetCmd = 0xBA; + +struct AHT10 { + float humidity = NAN; + float temperature = NAN; + uint8_t valid = 0; + uint8_t count = 0; + char name[6] = "AHT1x"; +} AHT10; + + +bool AHT10Read(void) +{ + unsigned long result_t, result_h, data[6]; + + if (AHT10.valid) { AHT10.valid--; } + + Wire.beginTransmission(AHT10_ADDR); + Wire.write(eSensorMeasureCmd, 3); + Wire.endTransmission(); + delay(100); + + Wire.requestFrom(AHT10_ADDR, 6); + for(uint8_t i = 0; Wire.available() > 0; i++) + { + data[i] = Wire.read(); + } + + result_h = ((data[1] << 16) | (data[2] << 8) | data[3]) >> 4; + result_t = ((data[3] & 0x0F) << 16) | (data[4] << 8) | data[5]; + + AHT10.humidity = result_h * 100 / 1048576; + AHT10.temperature = ((200 * result_t) / 1048576) - 50; + + if (isnan(AHT10.temperature) || isnan(AHT10.humidity)) { return false; } + + AHT10.valid = SENSOR_MAX_MISS; + return true; +} + +/********************************************************************************************/ +bool AHT10Init() +{ + Wire.begin(AHT10_ADDR); + Wire.beginTransmission(AHT10_ADDR); + Wire.write(eSensorCalibrateCmd, 3); + Wire.endTransmission(); + delay(500); + + if((AHT10ReadStatus() & 0x68) == 0x08) { + return true;} + else + { return false; } +} + +unsigned char AHT10ReadStatus(void) +{ + unsigned char result = 0; + Wire.requestFrom(AHT10_ADDR, 1); + result = Wire.read(); + return result; +} + +void AHT10Reset(void) +{ + Wire.beginTransmission(AHT10_ADDR); + Wire.write(eSensorResetCmd); + Wire.endTransmission(); + delay(20); +} + +/********************************************************************************************/ +void AHT10Detect(void) +{ + if (I2cActive(AHT10_ADDR)) + {return;} + + if (AHT10Init()) + { + I2cSetActiveFound(AHT10_ADDR, AHT10.name); + AHT10.count = 1; + } +} + +void AHT10EverySecond(void) +{ + if (uptime &1) { + // AHT10: 55mS + if (!AHT10Read()) { + AddLogMissed(AHT10.name, AHT10.valid); + } + } +} + +void AHT10Show(bool json) +{ + if (AHT10.valid) { + char temperature[33]; + dtostrfd(AHT10.temperature, Settings.flag2.temperature_resolution, temperature); + char humidity[33]; + dtostrfd(AHT10.humidity, Settings.flag2.humidity_resolution, humidity); + + if (json) { + ResponseAppend_P(JSON_SNS_TEMPHUM, AHT10.name, temperature, humidity); +#ifdef USE_DOMOTICZ + if ((0 == tele_period)) { + DomoticzTempHumSensor(temperature, humidity); + } +#endif // USE_DOMOTICZ +#ifdef USE_KNX + if (0 == tele_period) { + KnxSensor(KNX_TEMPERATURE, AHT10.temperature); + KnxSensor(KNX_HUMIDITY, AHT10.humidity); + } +#endif // USE_KNX +#ifdef USE_WEBSERVER + } else { + WSContentSend_PD(HTTP_SNS_TEMP, AHT10.name, temperature, TempUnit()); + WSContentSend_PD(HTTP_SNS_HUM, AHT10.name, humidity); +#endif // USE_WEBSERVER + } + } +} + +/*********************************************************************************************\ + * Interface +\*********************************************************************************************/ + +bool Xsns63(uint8_t function) +{ + if (!I2cEnabled(XI2C_43)) { return false; } + + bool result = false; + + if (FUNC_INIT == function) { + AHT10Detect(); + } + else if (AHT10.count) { + switch (function) { + case FUNC_EVERY_SECOND: + AHT10EverySecond(); + break; + case FUNC_JSON_APPEND: + AHT10Show(1); + break; +#ifdef USE_WEBSERVER + case FUNC_WEB_SENSOR: + AHT10Show(0); + break; +#endif // USE_WEBSERVER + } + } + return result; +} + +#endif // USE_AHT10 +#endif // USE_I2C