I have been sitting on the code for the Sensitron SHT25 sensor for a while now. I did some if it myself, most likely I collected some parts all over the net. I simply do not remember and therefore do not claim it to be my own. The template for the plugin was adapted from the SHT3x sensor. To put it short: seems to work fine with Arduino ESP Core 2.3.0 and Mega 2.0.
What it does:
provides four values.
1. Temperature and
2. Humidity (both measured) as well as
3. Absolute Humidity (calculated) and a
4. ventilation recommendation to avoide molt.
Commented out in the code there is also a dew point calculation but as the maximum of variables is 4 I put it aside.
It evaluates the checksum so communication should be safe.
The ventilation recommendation is based on "Isoplethensystem " - I gave the internet source in the code comment. I use it set my garage door to ventilation when the temp/hum combination becomes critical.
Usage:
1. have the ESPEasy project compile with the Arduino IDE.
2. Using the arrow on the right hand side add a new document.
3. paste the code in there. Compile.
That should be all.
I know that the proper way to contribute is via GitHub using a coding convention and so on. I am sorry, but I just do not have the time for that sort of deep dive. Still sharing in case anyone cares. If anyone of the main conributors cares to integrate my plugin permanently- I would be honored

Code: Select all
//#######################################################################################################
//################ Plugin 99: SHT25 Temperature and Humidity Sensor (I2C) ###################
//#######################################################################################################
//#ifdef PLUGIN_BUILD_TESTING
#define PLUGIN_099
#define PLUGIN_ID_099 99
#define PLUGIN_NAME_099 "Environment - SHT25 [TESTING]"
#define PLUGIN_VALUENAME1_099 "Temperature"
#define PLUGIN_VALUENAME2_099 "Humidity"
#define PLUGIN_VALUENAME3_099 "AbsoluteHumidity"
#define PLUGIN_VALUENAME4_099 "doVent"
//#define PLUGIN_VALUENAME5_099 "DewPoint" // max 4 variables allowed
//==============================================
// SHT2x LIBRARY - SHT2x.h
// =============================================
# ifndef SHT2x_H
# define SHT2x_H
typedef enum {
eTempHoldCmd = 0xE3,
eRHumidityHoldCmd = 0xE5,
eTempNoHoldCmd = 0xF3,
eRHumidityNoHoldCmd = 0xF5,
} HUM_MEASUREMENT_CMD_T;
class SHT2X
{
public:
SHT2X(uint8_t addr);
void get(void);
float tmp=0;
float hum=0;
float abshum=0;
//float dew=0;
float doVent=0;
float GetTemperature();
float GetHumidity();
float GetAbsoluteHumidity(float t, float h);
// float GetDewpoint (float t, float h);
bool GetDoVent(float t, float h);
private:
uint8_t _i2c_device_address;
uint16_t readSensor(uint8_t command);
uint8_t SHT2x_CheckCrc(uint8_t *data, uint8_t nbrOfBytes, uint8_t checksum);
};
#endif
//==============================================
// SHT2x LIBRARY - SHT2x.cpp
// =============================================
SHT2X::SHT2X(uint8_t addr)
{
_i2c_device_address = addr;
}
void SHT2X::get()
{
tmp = GetTemperature();
hum = GetHumidity();
abshum = GetAbsoluteHumidity (tmp,hum);
// dew = GetDewpoint(tmp,hum);
doVent = (float)GetDoVent(tmp,hum);
}
/**********************************************************
* GetHumidity
* Gets the current humidity from the sensor.
*
* @return float - The relative humidity in %RH
* return NaN in case of error.
**********************************************************/
float SHT2X::GetHumidity()
{
delay(50); // prevent interference from ongoing wifi transmissions
double H;
uint16_t val = readSensor(eRHumidityNoHoldCmd);
if (val) {
H = (-6.0 + 125.0 / 65536.0 * (double)(val));
return H;
}
else
return NAN;
}
/**********************************************************
* GetTemperature
* Gets the current temperature from the sensor.
*
* @return float - The temperature in Deg C
* return -100 in case of error.
**********************************************************/
float SHT2X::GetTemperature()
{
uint16_t val = readSensor(eTempNoHoldCmd);
double T;
if (val) {
T = (-46.85 + 175.72 / 65536.0 * (double)(val)); // read sensor and store value in internal variable
return T;
}
else
return NAN;
}
/**********************************************************
* GetDewPoint
* Calculates the dew point
* does not read the sensor
* @return float - The dew point in °C
**********************************************************/
/* max 4 variables per sensor :-(
float SHT2X::GetDewpoint(float t, float rh)
{
if (isnan(t) || isnan(rh) ) return NAN;
double H = (log10(rh)-2)/0.4343 + (17.62*t)/(243.12+t);
double Dp = 243.12*H/(17.62-H); // this is the dew point in Celsius
return Dp;
}
*/
/**********************************************************
* GetAbsoluteHumidity
* Gets the absolute humidity from the sensor.
* @return float - The abs humidity in grams/m3
**********************************************************/
float SHT2X::GetAbsoluteHumidity(float t, float rh)
{
if (isnan(t) || isnan(rh) ) return NAN;
double k1 = (17.67*t) / (t+253.5);
return (6.112*exp(k1) *rh*2.1674) / (273.15+t);
}
/**********************************************************
* GetDoVent
* Gets a recommendation to ventilate the room to prevent mold
* @return true/false
**********************************************************/
bool SHT2X::GetDoVent(float t, float rh){
// nach Isoplethensystem Schimmel http://images.google.de/imgres?imgurl=http%3A%2F%2Fdocplayer.org%2Fdocs-images%2F15%2F53845%2Fimages%2F12-1.jpg&imgrefurl=http%3A%2F%2Fdocplayer.org%2F53845-Leitfaden-zur-ursachensuche-und-sanierung-bei-schimmelpilzwachstum-in-innenraeumen-schimmelpilzsanierungs-leitfaden.html&h=744&w=471&tbnid=XxFIVIeNVxDG2M%3A&vet=1&docid=Ou59tpShUJ6CZM&ei=Ak4tWOiKMIiFgAbgwK-YDg&tbm=isch&iact=rc&uact=3&dur=1097&page=0&start=0&ndsp=52&ved=0ahUKEwjok-jclK_QAhWIAsAKHWDgC-MQMwgeKAMwAw&bih=1073&biw=1600
// Grenze: Formel: y = 0,00008x^4-0,0063x3 + 0,1883x2 - 2,7848x + 94,713
// x= Temperatur, y= Feuchte die nicht überschritten werden sollte
if (isnan(t) || isnan(rh) ) return NAN;
double b; // mold humidity
b=0.000038720*t*t*t*t;
b-=0.003965321*t*t*t;
b+=0.149368329*t*t;
b-=2.596918188*t;
b+=94.660142724;
if (rh>b)
return true;
else
return(false);
}
/**********************************************************
* Commnunications
**********************************************************/
uint16_t SHT2X::readSensor(uint8_t command)
{
// Wire.begin(mySDA, mySCL);
// delay(100);
Wire.begin();
int i = 0;
uint16_t result;
uint8_t checksum;
// blabla
Wire.beginTransmission(_i2c_device_address); //begin
delay(50);
Wire.write(command); //send the pointer location
Wire.endTransmission(); //end
delay(100); // wait for conversion
Wire.requestFrom(_i2c_device_address, 3);
while(Wire.available() < 3 && (i++) < 10) {
delay(10);
}
//Store the result
result = ((Wire.read()) << 8);
result += Wire.read();
checksum = Wire.read() ;
checksum = SHT2x_CheckCrc ((uint8_t*)&result,2,checksum);
result &= ~0x0003; // clear two low bits (status bits)
if (checksum>0)
return result;
else
return 0;
};
/**********************************************************
* Check CRC
**********************************************************/
uint8_t SHT2X::SHT2x_CheckCrc(uint8_t *data, uint8_t nbrOfBytes, uint8_t checksum)
{
uint8_t crc = 0;
uint8_t byteCtr;
const uint16_t POLYNOMIAL = 0x131; //P(x)=x^8+x^5+x^4+1 = 100110001
//calculates 8-Bit checksum with given polynomial
for (byteCtr = nbrOfBytes; byteCtr >0; byteCtr--)
{
crc ^= (data[byteCtr-1]);
for (uint8_t bit = 0; bit <8; bit++)
{ if (crc & 0x80) crc = (crc << 1) ^ POLYNOMIAL;
else crc = (crc << 1);
}
}
if (crc != checksum)
return 0;
else
return 1;
}
#ifndef CONFIG
#define CONFIG(n) (Settings.TaskDevicePluginConfig[event->TaskIndex][n])
#endif
SHT2X* Plugin_099_SHT2x = NULL;
//==============================================
// PLUGIN
// =============================================
boolean Plugin_099(byte function, struct EventStruct *event, String& string)
{
boolean success = false;
switch (function)
{
case PLUGIN_DEVICE_ADD:
{
Device[++deviceCount].Number = PLUGIN_ID_099;
Device[deviceCount].Type = DEVICE_TYPE_I2C;
Device[deviceCount].VType = SENSOR_TYPE_QUAD;
Device[deviceCount].Ports = 0;
Device[deviceCount].PullUpOption = false;
Device[deviceCount].InverseLogicOption = false;
Device[deviceCount].FormulaOption = true;
Device[deviceCount].ValueCount = 4;
Device[deviceCount].SendDataOption = true;
Device[deviceCount].TimerOption = true;
Device[deviceCount].GlobalSyncOption = true;
break;
}
case PLUGIN_GET_DEVICENAME:
{
string = F(PLUGIN_NAME_099);
break;
}
case PLUGIN_GET_DEVICEVALUENAMES:
{
strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_099));
strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[1], PSTR(PLUGIN_VALUENAME2_099));
strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[2], PSTR(PLUGIN_VALUENAME3_099));
strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[3], PSTR(PLUGIN_VALUENAME4_099));
// strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[4], PSTR(PLUGIN_VALUENAME5_099));
break;
}
case PLUGIN_WEBFORM_LOAD:
{
int optionValues[1] = { 0x40 };
addFormSelectorI2C(string, F("i2c_addr"), 1, optionValues, CONFIG(0));
success = true;
break;
}
case PLUGIN_WEBFORM_SAVE:
{
CONFIG(0) = getFormItemInt(F("i2c_addr"));
success = true;
break;
}
case PLUGIN_INIT:
{
if (Plugin_099_SHT2x)
delete Plugin_099_SHT2x;
Plugin_099_SHT2x = new SHT2X(CONFIG(0));
success = true;
break;
}
case PLUGIN_READ:
{
if (!Plugin_099_SHT2x)
return success;
Plugin_099_SHT2x->get();
UserVar[event->BaseVarIndex + 0] = Plugin_099_SHT2x->tmp;
UserVar[event->BaseVarIndex + 1] = Plugin_099_SHT2x->hum;
UserVar[event->BaseVarIndex + 2] = Plugin_099_SHT2x->abshum;
UserVar[event->BaseVarIndex + 3] = Plugin_099_SHT2x->doVent;
//UserVar[event->BaseVarIndex + 4] = Plugin_099_SHT2x->dew; // drop this one : vars per task is limited to 4
String log = F("SHT2x: Temperature: ");
log += UserVar[event->BaseVarIndex + 0];
addLog(LOG_LEVEL_INFO, log);
log = F("SHT2x: Humidity: ");
log += UserVar[event->BaseVarIndex + 1];
addLog(LOG_LEVEL_INFO, log);
log = F("SHT2x: AbsoluteHumidity: ");
log += UserVar[event->BaseVarIndex + 2];
addLog(LOG_LEVEL_INFO, log);
log = F("SHT2x: doVent: ");
log += UserVar[event->BaseVarIndex + 3];
addLog(LOG_LEVEL_INFO, log);
success = true;
break;
}
}
return success;
}
//#endif // testing