From dae1b329953cb8a5eb0c9d9ed15c5cda3aea425b Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Sat, 4 Jun 2022 16:52:52 +0200 Subject: [PATCH] Add support for Sensirion SHT4X using define USE_SHT3X (#15349) --- CHANGELOG.md | 1 + I2CDEVICES.md | 4 +- RELEASENOTES.md | 1 + tasmota/tasmota_xsns_sensor/xsns_14_sht3x.ino | 153 ++++++++++++------ 4 files changed, 108 insertions(+), 51 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1f996cef5..d12c0dcf7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ All notable changes to this project will be documented in this file. ## [11.1.0.4] ### Added - Support for HYTxxx temperature and humidity sensor (#15715) +- Support for Sensirion SHT4X using define USE_SHT3X (#15349) ### Changed - Restructured tasmota source directories taking benefit from PlatformIO Core v6.0.2 diff --git a/I2CDEVICES.md b/I2CDEVICES.md index f3af8c973..59bc03065 100644 --- a/I2CDEVICES.md +++ b/I2CDEVICES.md @@ -31,7 +31,8 @@ Index | Define | Driver | Device | Address(es) | Description 13 | USE_ADS1115 | xsns_12 | ADS1115 | 0x48 - 0x4B | 4-channel 16-bit A/D converter 14 | USE_INA219 | xsns_13 | INA219 | 0x40 - 0x41, 0x44 - 0x45 | Low voltage current sensor 15 | USE_SHT3X | xsns_14 | SHT3X | 0x44 - 0x45 | Temperature and Humidity sensor - 15 | USE_SHT3X | xsns_14 | SHTC3 | 0x70 | Temperature and Humidity sensor + 15 | USE_SHT3X | xsns_14 | SHT4X | 0x44 - 0x45 | Temperature and Humidity sensor + 15 | USE_SHT3X | xsns_14 | SHTCX | 0x70 | Temperature and Humidity sensor 16 | USE_TSL2561 | xsns_16 | TSL2561 | 0x29, 0x39, 0x49 | Light intensity sensor 17 | USE_MGS | xsns_19 | Grove | 0x04 | Multichannel gas sensor 18 | USE_SGP30 | xsns_21 | SGP30 | 0x58 | Gas (TVOC) and air quality sensor @@ -102,4 +103,3 @@ Index | Define | Driver | Device | Address(es) | Description 66 | USE_PCF85363 | xsns_99 | PCF85363 | 0x51 | Real time clock 67 | USE_DS3502 | xdrv_61 | DS3502 | 0x28 - 0x2B | Digital potentiometer 68 | USE_HYT | xsns_97 | HYTxxx | 0x28 | Temperature and Humidity sensor - \ No newline at end of file diff --git a/RELEASENOTES.md b/RELEASENOTES.md index ac74197cc..cbc4b42af 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -114,6 +114,7 @@ The latter links can be used for OTA upgrades too like ``OtaUrl http://ota.tasmo - Command ``SspmDisplay 2`` to display Sonoff SPM energy data in GUI for user tab-selected relay modules [#13447](https://github.com/arendst/Tasmota/issues/13447) - Support for Sonoff MS01 soil moisture sensor [#15335](https://github.com/arendst/Tasmota/issues/15335) - Support for daisy chaining MAX7219 displays [#15345](https://github.com/arendst/Tasmota/issues/15345) +- Support for Sensirion SHT4X using define USE_SHT3X [#15349](https://github.com/arendst/Tasmota/issues/15349) - Sonoff SPM delayed SetPowerOnState [#13447](https://github.com/arendst/Tasmota/issues/13447) - Support for Sonoff SPM v1.2.0 - Support for Sonoff Zigbee Bridge Pro by Stephan Hadinger [#15701](https://github.com/arendst/Tasmota/issues/15701) diff --git a/tasmota/tasmota_xsns_sensor/xsns_14_sht3x.ino b/tasmota/tasmota_xsns_sensor/xsns_14_sht3x.ino index 438ee601a..5a0f4b57d 100644 --- a/tasmota/tasmota_xsns_sensor/xsns_14_sht3x.ino +++ b/tasmota/tasmota_xsns_sensor/xsns_14_sht3x.ino @@ -1,7 +1,7 @@ /* - xsns_14_sht3x.ino - SHT3X temperature and humidity sensor support for Tasmota + xsns_14_sht3x.ino - SHT3X, SHT4X and SHTCX temperature and humidity sensor support for Tasmota - Copyright (C) 2021 Theo Arends + Copyright (C) 2022 Theo Arends, Stefan Tibus 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 @@ -20,85 +20,141 @@ #ifdef USE_I2C #ifdef USE_SHT3X /*********************************************************************************************\ - * SHT3X and SHTC3 - Temperature and Humidity + * Sensirion I2C temperature and humidity sensors * - * I2C Address: 0x44, 0x45 or 0x70 (SHTC3) + * This driver supports the following sensors: + * - SHT3x series: SHT30, SHT31, SHT35 (addresses: A: 0x44, B: 0x45) + * - SHTC series: SHTC1, SHTC3 (address: 0x70) + * - SHT4x series: SHT40, SHT41, SHT45 (addresses: A: 0x44, B: 0x45) \*********************************************************************************************/ #define XSNS_14 14 #define XI2C_15 15 // See I2CDEVICES.md -#define SHT3X_ADDR_GND 0x44 // address pin low (GND) -#define SHT3X_ADDR_VDD 0x45 // address pin high (VDD) -#define SHTC3_ADDR 0x70 // address for shtc3 sensor +#define SHT3X_ADDRESSES 2 // 2 addresses for SHT3x +#define SHT3X_ADDR_GND 0x44 // Address A pin low (GND) +#define SHT3X_ADDR_VDD 0x45 // Address B pin high (VDD) +#define SHTCX_ADDRESSES 1 // 1 address for SHTCx +#define SHTCX_ADDR 0x70 // Address for SHTCx sensors +#define SHT4X_ADDRESSES 2 // 2 addresses for SHT4x +#define SHT4X_ADDR_A 0x44 // Address SHT4x A +#define SHT4X_ADDR_B 0x45 // Address SHT4x B -#define SHT3X_MAX_SENSORS 3 +#define SHT3X_MAX_SENSORS 3 // Only one of 0x44, 0x45 and 0x70 -const char kShtTypes[] PROGMEM = "SHT3X|SHT3X|SHTC3"; -uint8_t sht3x_addresses[] = { SHT3X_ADDR_GND, SHT3X_ADDR_VDD, SHTC3_ADDR }; +enum SHT3X_Types { + SHT3X_TYPE_SHT3X, + SHT3X_TYPE_SHTCX, + SHT3X_TYPE_SHT4X +}; + +const char kSht3xTypes[] PROGMEM = "SHT3X|SHTC3|SHT4X"; +uint8_t sht3x_addresses[] = { SHT3X_ADDR_GND, SHT3X_ADDR_VDD, SHTCX_ADDR }; uint8_t sht3x_count = 0; struct SHT3XSTRUCT { - uint8_t address; // I2C bus address - char types[6]; // Sensor type name and address - "SHT3X-0xXX" + uint8_t type; // Sensor type + uint8_t address; // I2C bus address + char types[6]; // Sensor type name and address, e.g. "SHT3X" } sht3x_sensors[SHT3X_MAX_SENSORS]; -bool Sht3xRead(float &t, float &h, uint8_t sht3x_address) -{ - unsigned int data[6]; +uint8_t Sht3xComputeCrc(uint8_t data[], uint8_t len) { + // Compute CRC as per datasheet + uint8_t crc = 0xFF; + + for (uint8_t x = 0; x < len; x++) { + crc ^= data[x]; + for (uint8_t i = 0; i < 8; i++) { + if (crc & 0x80) { + crc = (crc << 1) ^ 0x31; + } else { + crc <<= 1; + } + } + } + return crc; +} + +bool Sht3xRead(uint32_t type, float &t, float &h, uint8_t i2c_address) { + uint8_t data[6]; t = NAN; h = NAN; - Wire.beginTransmission(sht3x_address); - if (SHTC3_ADDR == sht3x_address) { - Wire.write(0x35); // Wake from - Wire.write(0x17); // sleep - Wire.endTransmission(); - Wire.beginTransmission(sht3x_address); - Wire.write(0x78); // Disable clock stretching ( I don't think that wire library support clock stretching ) - Wire.write(0x66); // High resolution - } else { - Wire.write(0x2C); // Enable clock stretching - Wire.write(0x06); // High repeatability + Wire.beginTransmission(i2c_address); + switch (type) { + case SHT3X_TYPE_SHT3X: + // TODO: Clock stretching is used for SHT3x but not for SHTC3. Why? + Wire.write(0x2C); // Enable clock stretching + Wire.write(0x06); // High repeatability measurement + break; + case SHT3X_TYPE_SHTCX: + Wire.write(0x35); // Wake from + Wire.write(0x17); // sleep + Wire.endTransmission(); + Wire.beginTransmission(i2c_address); + // TODO: Clock stretching is used for SHT3x but not for SHTC3. Why? + Wire.write(0x78); // Disable clock stretching + Wire.write(0x66); // Normal mode measurement + break; + case SHT3X_TYPE_SHT4X: + Wire.write(0xFD); // High repeatability measurement + break; } - if (Wire.endTransmission() != 0) { // Stop I2C transmission + if (Wire.endTransmission() != 0) { // Stop I2C transmission return false; } - delay(30); // Timing verified with logic analyzer (10 is to short) - Wire.requestFrom(sht3x_address, (uint8_t)6); // Request 6 bytes of data + delay(30); // Timing verified with logic analyzer (10 is to short) + Wire.requestFrom(i2c_address, (uint8_t)6); // Request 6 bytes of data for (uint32_t i = 0; i < 6; i++) { - data[i] = Wire.read(); // cTemp msb, cTemp lsb, cTemp crc, humidity msb, humidity lsb, humidity crc + data[i] = Wire.read(); // temperature (MSB, LSB, CRC), humidity (MSB, LSB, CRC) }; + if ((Sht3xComputeCrc(&data[0], 2) != data[2]) || (Sht3xComputeCrc(&data[3], 2) != data[5])) { + return false; + } t = ConvertTemp((float)((((data[0] << 8) | data[1]) * 175) / 65535.0) - 45); h = ConvertHumidity((float)((((data[3] << 8) | data[4]) * 100) / 65535.0)); - return (!isnan(t) && !isnan(h) && (h != 0)); + return (!isnan(t) && !isnan(h)); } /********************************************************************************************/ -void Sht3xDetect(void) -{ +void Sht3xDetect(void) { + float t; + float h; + for (uint32_t i = 0; i < SHT3X_MAX_SENSORS; i++) { if (!I2cSetDevice(sht3x_addresses[i])) { continue; } - float t; - float h; - if (Sht3xRead(t, h, sht3x_addresses[i])) { - sht3x_sensors[sht3x_count].address = sht3x_addresses[i]; - GetTextIndexed(sht3x_sensors[sht3x_count].types, sizeof(sht3x_sensors[sht3x_count].types), i, kShtTypes); - I2cSetActiveFound(sht3x_sensors[sht3x_count].address, sht3x_sensors[sht3x_count].types); - sht3x_count++; + if (i < 2) { // 0x44 and 0x45 + sht3x_sensors[sht3x_count].type = SHT3X_TYPE_SHT3X; + if (!Sht3xRead(sht3x_sensors[sht3x_count].type, t, h, sht3x_addresses[i])) { + sht3x_sensors[sht3x_count].type = SHT3X_TYPE_SHT4X; + if (!Sht3xRead(sht3x_sensors[sht3x_count].type, t, h, sht3x_addresses[i])) { + continue; + } + } + } else { // 0x70 + sht3x_sensors[sht3x_count].type = SHT3X_TYPE_SHTCX; + if (!Sht3xRead(sht3x_sensors[sht3x_count].type, t, h, sht3x_addresses[i])) { + continue; + } } + sht3x_sensors[sht3x_count].address = sht3x_addresses[i]; + GetTextIndexed(sht3x_sensors[sht3x_count].types, sizeof(sht3x_sensors[sht3x_count].types), SHT3X_TYPE_SHT3X, kSht3xTypes); + I2cSetActiveFound(sht3x_sensors[sht3x_count].address, sht3x_sensors[sht3x_count].types); + sht3x_count++; } } -void Sht3xShow(bool json) -{ +void Sht3xShow(bool json) { + float t; + float h; + char types[11]; + for (uint32_t i = 0; i < sht3x_count; i++) { - float t; - float h; - if (Sht3xRead(t, h, sht3x_sensors[i].address)) { - char types[11]; + if (Sht3xRead(sht3x_sensors[i].type, t, h, sht3x_sensors[i].address)) { + t = ConvertTemp(t); + h = ConvertHumidity(h); strlcpy(types, sht3x_sensors[i].types, sizeof(types)); if (sht3x_count > 1) { snprintf_P(types, sizeof(types), PSTR("%s%c%02X"), sht3x_sensors[i].types, IndexSeparator(), sht3x_sensors[i].address); // "SHT3X-0xXX" @@ -112,8 +168,7 @@ void Sht3xShow(bool json) * Interface \*********************************************************************************************/ -bool Xsns14(uint8_t function) -{ +bool Xsns14(uint8_t function) { if (!I2cEnabled(XI2C_15)) { return false; } bool result = false; @@ -137,4 +192,4 @@ bool Xsns14(uint8_t function) } #endif // USE_SHT3X -#endif // USE_I2C +#endif // USE_I2C \ No newline at end of file