Arduino library for the SHT2x, HTU2x and Si70xx temperature and humidity sensors.
This library is not tested extensively yet. It works for the Si7021 including the asynchronous interface. It should work for SHT20, SHT21 and SHT25 but these are not tested yet. The SHT2x family of sensors should work up to 400 KHz I2C.
Furthermore there are several other sensors that should be compatible (see table below), but have not been tested either.
Accuracy table
| Sensor | Temperature | Humidity | Notes |
|---|---|---|---|
| SHT20 | ~0.3 | ±3.0 | |
| SHT21 | ~0.3 | ±3.0 | |
| SHT25 | ~0.3 | ±1.8 | |
| HTU20 | to-do | ||
| HTU21 | to-do | ||
| Si7013 | to-do | ||
| Si7020 | to-do | ||
| Si7021 | ~0.3 | ~2.0 | |
| GY21 | to-do |
All sensors in this family of sensors have address 0x40 (64 decimal). If you want to use more on one I2C bus one needs either an I2C multiplexer or one should switch sensors on/off like the select in SPI communication.
Version 0.5.0 introduced a breaking change. You cannot set the pins in begin() any more. This reduces the dependency of processor dependent Wire implementations. The user has to call Wire.begin() and can optionally set the Wire pins before calling begin().
- https://github.com/RobTillaart/SHT31
- https://github.com/RobTillaart/SHT85
- https://github.com/RobTillaart/tinySHT2x
#include "SHT2x.h"The SHT2x library provides a comprehensive interface for interacting with SHT2x, HTU2x, and Si70xx series temperature and humidity sensors.
These constructors initialize a sensor object. All specific sensor classes (SHT20, Si7021, etc.) are derived from the base SHT2x class.
- SHT2x(TwoWire *wire = &Wire): Base class constructor. Optionally takes a pointer to a
TwoWireinterface, allowing usage with multiple I2C buses on platforms that support it. - SHT20(TwoWire *wire = &Wire): Constructor for SHT20 sensors.
- SHT21(TwoWire *wire = &Wire): Constructor for SHT21 sensors.
- SHT25(TwoWire *wire = &Wire): Constructor for SHT25 sensors.
- HTU20(TwoWire *wire = &Wire): Constructor for HTU20 sensors.
- HTU21(TwoWire *wire = &Wire): Constructor for HTU21 sensors.
- Si7013(TwoWire *wire = &Wire): Constructor for Si7013 sensors.
- Si7020(TwoWire *wire = &Wire): Constructor for Si7020 sensors.
- Si7021(TwoWire *wire = &Wire): Constructor for Si7021 sensors.
- GY21(TwoWire *wire = &Wire): Constructor for GY21 sensor modules (often using SHT2x compatible sensors).
These functions provide fundamental control and status information for the sensor.
- bool begin(): Initializes the sensor. This function calls
reset()internally, which can take up to 15 ms. Returnsfalseif the device address is not reachable or if the sensor fails to reset. - bool isConnected(): Checks if the sensor is reachable over the I2C bus. Returns
falseif the sensor is not connected or does not acknowledge. - bool reset(): Performs a soft reset of the sensor. This can take up to 15 ms. Hard reset is not supported by this library.
- uint32_t lastRead(): Returns the timestamp (in milliseconds since program start) of the last successful
read()operation. - uint8_t getStatus(): Returns a 2-bit status code indicating the sensor's current operational state. See the "Status fields" table for details on interpreting these bits.
These functions are used for synchronous (blocking) reads of temperature and humidity.
- bool read(): Reads both temperature and humidity from the sensor. This is a blocking call; program execution will pause until the readings are complete.
- float getTemperature(): Returns the temperature in degrees Celsius (°C) based on the latest raw data acquired by
read(). - float getHumidity(): Returns the relative humidity in percent (%) based on the latest raw data acquired by
read(). - uint16_t getRawTemperature(): Returns the raw, not calibrated 16-bit integer value for temperature directly from the sensor, as acquired by
read(). - uint16_t getRawHumidity(): Returns the raw, not calibrated 16-bit integer value for humidity directly from the sensor, as acquired by
read().
Note on read() and data retrieval:
The getTemperature() and getHumidity() functions recalculate values from raw data on every call. If performance is critical, cache these values in your code after a read() instead of calling them repeatedly. Raw values are useful for minimizing storage or communication overhead.
The Si70xx sensors (Si7013, Si7020, Si7021) also support reading the temperature value that was internally measured during the last humidity acquisition. This can be useful to get a temperature reading without initiating a new, separate temperature measurement.
- bool readCachedTemperature(): For Si70xx sensors, this function retrieves the temperature value measured during the last humidity reading. This is available after a
getHumidity()call (using the synchronousread()method) or after arequestHumidity()and successfulreadHumidity()(using the asynchronous interface). See pull request #27 comment for more details on calling sequences.
The asynchronous interface allows you to initiate a temperature or humidity reading and then continue with other tasks while the sensor is performing the measurement. This is useful for non-blocking applications, preventing your main loop from being stalled while waiting for sensor data. This interface is experimental (since 0.2.2) and may change in future versions. See discussion in issue #16.
General Workflow for Asynchronous Operations:
- Initiate a request: Call
requestTemperature()to start a temperature measurement orrequestHumidity()to start a humidity measurement. The library sends the command to the sensor, which then begins its internal conversion process. - Periodically check for data readiness: In your main loop or a timed function, call
reqTempReady()(for temperature) orreqHumReady()(for humidity) to see if the sensor has finished its measurement. These functions returntrueif data is available,falseotherwise.requestReady()can be used to check if any requested data is ready. - Read the value: Once the corresponding "ready" function returns
true, callreadTemperature()to retrieve the temperature value orreadHumidity()to retrieve the humidity value. These functions then fetch the data from the sensor and update the internal raw values. You can then usegetTemperature()orgetHumidity()to get the processed values.
Difference between synchronous read() and asynchronous operations:
- Synchronous
read(): When you callread(), your program stops and waits for the sensor to complete both temperature and humidity measurements. This is simpler to use but can block other operations for the duration of the sensor's measurement time (which can be tens of milliseconds). - Asynchronous functions: You explicitly manage the measurement process. You start a measurement, can perform other tasks, and then check back later to retrieve the result. This avoids blocking but requires a slightly more complex program structure to periodically check the sensor's status.
Asynchronous Function Descriptions:
bool requestTemperature(): Initiates a request for a temperature reading from the sensor. If a previous asynchronous request (either temperature or humidity) was still pending, it will be overridden by this new request. Returnstrueif the request command was successfully sent to the sensor,falseotherwise (e.g., I2C communication error).bool requestHumidity(): Initiates a request for a humidity reading from the sensor. If a previous asynchronous request was pending, it will be overridden. Returnstrueif the request command was successfully sent,falseotherwise.bool reqTempReady(): Checks if the temperature data previously requested byrequestTemperature()is ready to be read from the sensor. Returnstrueif data is available,falseif the measurement is still in progress or if no temperature request was made.bool reqHumReady(): Checks if the humidity data previously requested byrequestHumidity()is ready to be read. Returnstrueif data is available,falseif the measurement is still in progress or if no humidity request was made.bool requestReady(): Checks if any previously requested asynchronous data (either temperature or humidity) is ready. This is useful if you don't need to distinguish which type of data is ready, only that some data can be read. Returnstrueif either temperature or humidity data is available.bool readTemperature()(in asynchronous context): Reads the temperature data from the sensor afterrequestTemperature()has been called andreqTempReady()has returnedtrue. This function fetches the raw data from the sensor. After this call,getTemperature()andgetRawTemperature()will return the newly acquired values. Returnstrueif the read was successful,falseotherwise (e.g., CRC error, I2C error).bool readHumidity()(in asynchronous context): Reads the humidity data from the sensor afterrequestHumidity()has been called andreqHumReady()has returnedtrue. This function fetches the raw data. After this call,getHumidity()andgetRawHumidity()will return the newly acquired values. Returnstrueif the read was successful,falseotherwise.uint32_t lastRequest(): Returns the timestamp (in milliseconds, based onmillis()) of when the last asynchronous request (requestTemperature()orrequestHumidity()) was made. This can be useful for implementing timeouts for asynchronous operations.uint8_t getRequestType(): Returns the type of the currently pending or last completed asynchronous request. This helps in determining what kind of data was requested or is ready. The possible return values are:
| Value | Symbolic | Description |
|---|---|---|
| 0x00 | SHT2x_REQ_NONE |
No request pending or last request completed/cleared. |
| 0x01 | SHT2x_REQ_TEMPERATURE |
A temperature request is currently pending or was the last one made. |
| 0x02 | SHT2x_REQ_HUMIDITY |
A humidity request is currently pending or was the last one made. |
| 0xFF | SHT2x_REQ_FAIL |
A humidity request is currently pending or was the last one made. |
Example Snippet (Asynchronous Reading):
#include "SHT2x.h"
#include "Wire.h"
SHT21 sht; // Or SHT20, SHT25, Si7021, etc.
void setup() {
Serial.begin(115200);
Wire.begin();
if (!sht.begin()) {
Serial.println("SHT2x sensor not found!");
while (1);
}
Serial.println("SHT2x sensor initialized.");
// Request initial temperature reading
if (!sht.requestTemperature()) {
Serial.println("Failed to request temperature.");
}
}
void loop() {
// Non-blocking check for temperature data
if (sht.getRequestType() == SHT2x_REQ_TEMPERATURE && sht.reqTempReady()) {
if (sht.readTemperature()) {
Serial.print("Temperature: ");
Serial.print(sht.getTemperature());
Serial.println(" °C");
// Now request humidity
if (!sht.requestHumidity()) {
Serial.println("Failed to request humidity.");
}
} else {
Serial.println("Failed to read temperature.");
// Optionally, re-request temperature or handle error
if (!sht.requestTemperature()) {
Serial.println("Failed to re-request temperature.");
}
}
}
// Non-blocking check for humidity data
if (sht.getRequestType() == SHT2x_REQ_HUMIDITY && sht.reqHumReady()) {
if (sht.readHumidity()) {
Serial.print("Humidity: ");
Serial.print(sht.getHumidity());
Serial.println(" %");
// Now request temperature for the next cycle
if (!sht.requestTemperature()) {
Serial.println("Failed to request temperature for next cycle.");
}
} else {
Serial.println("Failed to read humidity.");
// Optionally, re-request humidity or handle error
if (!sht.requestHumidity()) {
Serial.println("Failed to re-request humidity.");
}
}
}
// Do other non-blocking things in your loop here
// For example, yield() or delay(1) can be used if appropriate
// to prevent busy-waiting, depending on the platform.
// A simple delay to slow down serial output for this example:
delay(100);
}Waiting until the device is ready:
These sensors typically need a bit of time to start up before they can accept commands. The SHT21, for instance, requires up to 15ms after it's been powered up. In many programs, the delay that the Arduino framework introduces between your setup() and loop() functions is sufficient, but if you intend to request your first reading in setup() immediately after calling begin(), the request may fail. If requestTemperature() or requestHumidity() returns false and the error code returned from getError() is 0x81 (SHT2x_ERR_WRITECMD), this may be a sign that the sensor isn't ready.
To work around this, introduce a short delay after calling begin() and before requesting a reading. 15ms is probably more than sufficient, although this hasn't been tested extensively.
The built-in heater can be used to test the sensor or to drive off condensation.
WARNING: Do not use the heater for long periods. The datasheet for SHT2x sensors does not specify a maximum on-time, so the library conservatively uses the SHT3x series guideline:
Use the heater for a maximum of 180 seconds (3 minutes), then allow it to cool down for at least 180 seconds. The library enforces a cool-down period by preventing heatOn() from succeeding if called within 180 seconds of the last heatOff() call. This guarding is not reboot persistent.
WARNING: The user is responsible for switching the heater off manually using heatOff(). The library does NOT do this automatically.
- void setHeatTimeout(uint8_t seconds): Sets the duration (in seconds) for the heater to be active when
heatOn()is called. This value is capped at a maximum of 180 seconds. - uint8_t getHeatTimeout(): Returns the currently set heat timeout value in seconds.
- bool heatOn(): Turns the internal heater on. Returns
falseif the heater cannot be turned on (e.g., during the mandatory cool-down period or if I2C communication fails), setting an error code (SHT2x_ERR_HEATER_COOLDOWN or SHT2x_ERR_HEATER_ON). - bool heatOff(): Turns the internal heater off. Returns
falseif the heater cannot be switched off (e.g., I2C communication error), setting the SHT2x_ERR_HEATER_OFF error. - bool isHeaterOn(): Checks if the heater is currently active (i.e., within the
_heatTimeoutperiod sinceheatOn()was called and beforeheatOff()is called). Calling this function will also turn the heater off if the timeout has expired. - bool setHeaterLevel(uint8_t level): Sets the heater power level. The level is a value from 0 to 15. (Note: This function's availability might depend on the specific sensor model; refer to the sensor datasheet.)
- bool getHeaterLevel(uint8_t &level): Reads the current heater power level. (Note: Availability might depend on the specific sensor model.)
Functions to retrieve the unique electronic identification code and firmware version from the sensor. (These functions need more testing and have primarily been tested with Si7021 sensors.)
- uint32_t getEIDA(): Returns the first part (A) of the electronic ID.
- uint32_t getEIDB(): Returns the second part (B) of the electronic ID.
- uint8_t getFirmwareVersion(): Returns the firmware version of the sensor.
Allows adjustment of the measurement resolution for temperature and humidity.
Warning: This feature is experimental (since 0.2.0) and requires more testing, as initial results are not perfectly aligned with datasheet specifications. It has been primarily tested on HTUxx and Si7021 sensors using the SHT2X_resolution.ino example.
- bool setResolution(uint8_t res): Sets the measurement resolution.
rescan be 0, 1, 2, or 3. Other values will result in the function returningfalse. - uint8_t getResolution(): Returns the currently set resolution (cached value).
Datasheet SHT20 Table 8: Resolution settings
| RES | Humidity | Temperature |
|---|---|---|
| 0 | 12 bit | 14 bit |
| 1 | 08 bit | 12 bit |
| 2 | 10 bit | 13 bit |
| 3 | 11 bit | 11 bit |
Datasheet SHT20 Table 7: Measurement timing (milliseconds) vs. observed real-world measurements. (See details at #11)
| RES | HUM (datasheet) | TEMP (datasheet) | TOTAL (datasheet) | REAL (observed) |
|---|---|---|---|---|
| 0 | 29 | 85 | 114 | 116 |
| 1 | 4 | 22 | 26 | 113 |
| 2 | 9 | 43 | 52 | 084 |
| 3 | 15 | 11 | 26 | 102 |
- bool batteryOK(): Checks the sensor's battery status indicator. Returns
trueif VCC is above approximately 2.25V (threshold may vary slightly by sensor). Not all sensors support this feature.
- int getError(): Returns the last error code set by a library function and then clears the internal error flag. It's important to call
getError()to check for errors after sensor operations, especially if a function returnsfalse. CallinggetError()before another operation ensures you are checking the result of the most recent operation.
Error Codes:
| Value | Symbolic | Description | Notes |
|---|---|---|---|
| 0x00 | SHT2x_OK | No error | |
| 0x81 | SHT2x_ERR_WRITECMD | I2C write command failed | |
| 0x82 | SHT2x_ERR_READBYTES | I2C read bytes failed | |
| 0x83 | SHT2x_ERR_HEATER_OFF | Could not switch off heater | |
| 0x84 | SHT2x_ERR_NOT_CONNECT | Could not connect to sensor | |
| 0x85 | SHT2x_ERR_CRC_TEMP | CRC check failed for temperature | |
| 0x86 | SHT2x_ERR_CRC_HUM | CRC check failed for humidity | |
| 0x87 | SHT2x_ERR_CRC_STATUS | CRC check failed for status reg | Not used |
| 0x88 | SHT2x_ERR_HEATER_COOLDOWN | Heater needs to cool down | |
| 0x89 | SHT2x_ERR_HEATER_ON | Could not switch on heater | (Note: 0x88 was duplicated in original, assuming 0x89 for HEATER_ON based on .h) |
| 0x8A | SHT2x_ERR_RESOLUTION | Invalid resolution setting | Added in 0.2.0 |
Note: HTU20 / HTU21 classes share these error codes. The error SHT2x_ERR_HEATER_ON was listed with code 0x88 in the original README but is 0x89 in SHT2x.h; this table uses 0x89.
The getStatus() function returns a 2-bit value that indicates the type of measurement in the last user register read.
From HTU20 datasheet (consult your specific sensor's datasheet for definitive details).
| Bits | Value | Symbolic | Description |
|---|---|---|---|
| 00 | 0 | SHT2x_STATUS_OPEN_CIRCUIT | Open circuit |
| 01 | 1 | SHT2x_STATUS_TEMPERATURE | Temperature reading |
| 10 | 2 | SHT2x_STATUS_HUMIDITY | Humidity reading |
| 11 | 3 | SHT2x_STATUS_CLOSED_CIRCUIT | Closed circuit |
- improve documentation
- reorganize interface
- async documentation
- clean up code.
- test test test
- get hardware
- add examples
- test resolutions
- performance different resolutions
- test battery
- fix TODO in code (.cpp and .h) and documentation
- update unit tests
- add type info in derived classes?
- add getSerialNumber() getEIDA() and getEIDB() covers this
If you appreciate my libraries, you can support the development and maintenance. Improve the quality of the libraries by providing issues and Pull Requests, or donate through PayPal or GitHub sponsors.
Thank you,