arendst / Tasmota

Alternative firmware for ESP8266 and ESP32 based devices with easy configuration using webUI, OTA updates, automation using timers or rules, expandability and entirely local control over MQTT, HTTP, Serial or KNX. Full documentation at
https://tasmota.github.io/docs
GNU General Public License v3.0
21.98k stars 4.77k forks source link

ADD:Humidity compensation for SGP30 #5579

Closed TONGXD closed 5 years ago

TONGXD commented 5 years ago

What should I do?

The SGP30 features an on-chip humidity compensation for the air quality signals (CO2eq and TVOC) and sensor raw signals (H2-signal and Ethanol_signal). To use the on-chip humidity compensation an absolute humidity value from an external humidity sensor like the SHTxx is required.

ascillato2 commented 5 years ago

Hi,

According to the SGP30 datasheet that compensation is possible.

Tasmota is using the adafruit library 1.0.2 that does not have the commands for applying that compensation, but it is supported on the new adafruit library 1.0.3 from https://github.com/adafruit/Adafruit_SGP30

So, it is needed to update the library in Tasmota codebase and modify the SGP driver to allow using humidity as input. I think a new sensor command is needed to choose to apply or not this compensation.

Adding the label enhancement to this issue.

Thanks for sharing your ideas :+1:

arendst commented 5 years ago

Tasmota has a hidden feature which stores temp and hum of a connected device in a global struct. The info in this struct can be used by any sensor needing this information for whatever reason.

So all that is needed is adding some code to the SGP30 sensor driver to get this global data. Sounds simple ;-)

gemu2015 commented 5 years ago

unfortunately it is not that easy! the SGP30 needs ABSOLUTE humidity with is very complicated to calculate and needs relative humidity, temperature and air pressure.

gemu2015 commented 5 years ago

as it turns out that absolute humidity (as in contrast to relative humidity) is the factor that determines if viruses can survive in an environment (https://www.ncbi.nlm.nih.gov/pmc/articles/PMC2893471/) it would be very interesting to have it. since the bme280 provides all the necessary input, absolute humidity should be implemented there. it then can also be used for compensation of the sgp30.

the formula however is a monster and uses some flash and time consuming functions =>

abs_hum=0.622 In_RelHum/100 (1.01325 10^(5.426651 - 2005.1 / (InTemp + 273.15) + 0.00013869 ((InTemp + 273.15) (InTemp + 273.15) - 293700) / (InTemp + 273.15) (10^(0.000000000011965 ((InTemp + 273.15) (InTemp + 273.15) - 293700) ((InTemp + 273.15) (InTemp + 273.15) - 293700)) - 1) - 0.0044 10^((-0.0057148 (374.11 - InTemp)^1.25))) + (((InTemp + 273.15) / 647.3) - 0.422) (0.577 - ((InTemp + 273.15) / 647.3)) EXP(0.000000000011965 ((InTemp + 273.15) (InTemp + 273.15) - 293700) ((InTemp + 273.15) (InTemp + 273.15) - 293700)) 0.00980665) / (In_Pressure/1000 - In_RelHum/100 (1.01325 10^(5.426651 - 2005.1 / (InTemp + 273.15) + 0.00013869 ((InTemp + 273.15) (InTemp + 273.15) - 293700) / (InTemp + 273.15) (10^(0.000000000011965 ((InTemp + 273.15) (InTemp + 273.15) - 293700) ((InTemp + 273.15) (InTemp + 273.15) - 293700)) - 1) - 0.0044 10^((-0.0057148 (374.11 - InTemp)^1.25))) + (((InTemp + 273.15) / 647.3) - 0.422) (0.577 - ((InTemp + 273.15) / 647.3)) EXP(0.000000000011965 ((InTemp + 273.15) (InTemp + 273.15) - 293700) ((InTemp + 273.15) (InTemp + 273.15) - 293700)) 0.00980665)) In_Pressure/1000 100000000 / ((InTemp + 273.15) 287.1)

i am short of time but i will definitely implement this if nobody else will.

digging a bit further gives a simplified version ignoring pressure (don't know the error induced)

in the bme280 GitHub =>https://github.com/finitespace/BME280/blob/master/src/EnvironmentCalculations.cpp

gemu2015 commented 5 years ago

since most calculations found on the web don't use pressure i did take the much simpler calculation from bme280 and implemented this to the sgp30 driver. i also did put the absolute humidity value to the web gui and json output of the sgp30

if you want to try take it from my fork =>https://github.com/gemu2015/Sonoff-Tasmota (take over the sgp30 lib and the sgp30 driver)

if it is tested for i while i can make a pr to tasmota

joba-1 commented 5 years ago

Hi @gemu2015, impressive formula, it got me hooked :) Comparing what I saw here (https://planetcalc.com/2161 and https://planetcalc.com/2167) it seems overly complicated though - even with using pressure. The pressure term is just f(p) = 1,0016 + 0,00000315 * p - 0,074 / p and within valid values of the bme280 this varies absolute humidity by less than 0,1% so you can really ignore it for normal atmospheric pressures.

Btw, I looked at your github repo and have a suggestion: it would be much easier to pick up features if you would implement them in branches and then merge to your master

Jason2866 commented 5 years ago

@TONGXD Look in GEMUs fork. He worked on it :-) GEMU Fork Tasmota

TONGXD commented 5 years ago

get the humidity value of si7021 ↓↓↓↓↓↓↓↓↓↓ https://github.com/sparkfun/SparkFun_SGP30_Arduino_Library

TONGXD commented 5 years ago

Thanks

ascillato2 commented 5 years ago

Reopening this issue until the enhancement is added to Tasmota. Waiting for the PR from @gemu2015

Littlesloths commented 3 years ago

It would be very useful for me, too. I did not see the absolute humidity item on the list @gemu2015 ? @gemu2015: will you bring it in? or, if not maybe someone else could copy it from that branch?

ascillato commented 3 years ago

Already merged. See #5817 that is also linked above.

Littlesloths commented 3 years ago

Thank you. Like in #5817 mentioned the absolute humidity could be calculated and provided for all sensors with temperature and relative humidity. What needs to be done that all sensors like BM280 or AM2301 also get abs. humidity as an output?

pkkrusty commented 2 years ago

Also interested in this issue. For my purposes, with a SHT3X sensor, absolute humidity is more useful for looking at long-term atmospheric moisture levels, vs relative humidity levels, which are more useful for interpreting human comfort/feel.

Other calculations for enthalpy, partial pressure, and mixing ratio would be possible with a little more math, but don't know the ram/processing requirements. The following document is helpful for formulas:

https://www.hatchability.com/Vaisala.pdf

Would it be possible to define a variable for atmospheric pressure? Ideal would be a sensor that passes pressure to a global variable, but in the absence of that, defining an average pressure manually would yield pretty accurate results.

Littlesloths commented 2 years ago

Hi pkkrusty, for my part I did the math in node red. The convertion is not that complicated to implement (first temperature&rel. humidity > dewpoint, then dewpoint & temp > abs humidity), but not sure if it's possible to implement it as a script. Of course I'd still like to get it implemented in tasmota directly for purposes of getting around node red.

pkkrusty commented 2 years ago

Yep, not hard to do in Node-Red or grafana, which is what I'm currently doing, but esp8266 should be able to handle it, and makes things less complicated. Wish I had the skills to implement, but I'll have to wait until someone smart decides it's worth their time.

pkkrusty commented 2 years ago

FWIW: I took a stab at adding the necessary formulas in support.ino, but there's lots of integration work to do to get it into the Webserver and JSON reporting etc.

float CalcAbsHum(float t, float h)
{
  if (isnan(h) || isnan(t)) { return NAN; }

  if (Settings->flag.temperature_conversion) {                 // SetOption8 - Switch between Celsius or Fahrenheit
    t = (t - 32) / 1.8;                                       // Celsius
  }

// formula from https://www.hatchability.com/Vaisala.pdf - Simplified equation with 0.083% max error from -20 - 50ºC

  float result = (((6.116441*10^(7.591386*t/(t+240.7263)))*h/100)/(t+273.15))*2.16679*100;

  return result;  // units are g/m^3
}

float CalcMixingRatio(float t, float h, float p)
{
  if (isnan(h) || isnan(t)) { return NAN; }

  if (Settings->flag.temperature_conversion) {                 // SetOption8 - Switch between Celsius or Fahrenheit
    t = (t - 32) / 1.8;                                       // Celsius
  }

  if (isnan(p)) {
    p = 1013.25;                                              // Average pressure in pascals at sea level
  }

  // formula from https://www.hatchability.com/Vaisala.pdf - Simplified equation with 0.083% max error from -20 - 50ºC

  float result = 6.116441*10^(7.591386*t/(t+240.7263))*621.9907/(p-(6.116441*10^(7.591386*t/(t+240.7263))))*h/100;

  return result; // units are g/kg
}