SHT25 plugin

Moderators: grovkillen, Stuntteam, TD-er

Post Reply
Message
Author
s0170071
Normal user
Posts: 36
Joined: 21 Oct 2017, 20:49

SHT25 plugin

#1 Post by s0170071 » 21 Oct 2017, 21:34

Hi all,

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 :D




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


Post Reply

Who is online

Users browsing this forum: No registered users and 28 guests