Add support for US AQI and EPA AQI in PMS5003x sensors (#22294)

This commit is contained in:
Theo Arends 2024-10-25 14:44:42 +02:00
parent 16a145f809
commit 73cd5cee25
4 changed files with 84 additions and 4 deletions

View File

@ -15,6 +15,7 @@ All notable changes to this project will be documented in this file.
- DALI inverted signal configuration using GPIO DALI RX_i/TX_i
- Support for Shelly DALI Dimmer Gen3 (See tips and template in file xdrv_75_dali.ino)
- HASPmota `haspmota.get_pages()` to get the sorted list of pages (#22358)
- Support for US AQI and EPA AQI in PMS5003x sensors (#22294)
### Breaking Changed

View File

@ -122,6 +122,7 @@ The latter links can be used for OTA upgrades too like ``OtaUrl https://ota.tasm
- DALI command `DaliTarget` to set light control broadcast, group number or gear number
- DALI inverted signal configuration using GPIO DALI RX_i/TX_i
- Support for Shelly DALI Dimmer Gen3 (See tips and template in file xdrv_75_dali.ino)
- Support for US AQI and EPA AQI in PMS5003x sensors [#22294](https://github.com/arendst/Tasmota/issues/22294)
- Mitsubishi Electric HVAC Operation time for MiElHVAC [#22334](https://github.com/arendst/Tasmota/issues/22334)
- Mitsubishi Electric HVAC Outdoor Temperature for MiElHVAC [#22345](https://github.com/arendst/Tasmota/issues/22345)
- Mitsubishi Electric HVAC Compressor Frequency for MiElHVAC [#22347](https://github.com/arendst/Tasmota/issues/22347)

View File

@ -1006,7 +1006,9 @@ const char HTTP_SNS_STANDARD_CONCENTRATION[] PROGMEM = "{s}%s " D_STANDAR
const char HTTP_SNS_ENVIRONMENTAL_CONCENTRATION[] PROGMEM = "{s}%s " D_ENVIRONMENTAL_CONCENTRATION " %s " D_UNIT_MICROMETER "{m}%d " D_UNIT_MICROGRAM_PER_CUBIC_METER "{e}";
const char HTTP_SNS_F_ENVIRONMENTAL_CONCENTRATION[] PROGMEM = "{s}%s " D_ENVIRONMENTAL_CONCENTRATION " %s " D_UNIT_MICROMETER "{m}%1_f " D_UNIT_MICROGRAM_PER_CUBIC_METER "{e}";
const char HTTP_SNS_PARTICALS_BEYOND[] PROGMEM = "{s}%s " D_PARTICALS_BEYOND " %s " D_UNIT_MICROMETER "{m}%d " D_UNIT_PARTS_PER_DECILITER "{e}";
const char HTTP_SNS_AVG_RAD_DOSE[] PROGMEM = "{s}%s " D_AVG_RAD_DOSE " %s " D_UNIT_MINUTE "{m}%d.%02d " D_UNIT_US_H "{e}";
const char HTTP_SNS_AVG_RAD_DOSE[] PROGMEM = "{s}%s " D_AVG_RAD_DOSE " %s " D_UNIT_MINUTE "{m}%d.%02d " D_UNIT_US_H "{e}";
const char HTTP_SNS_US_AQI[] PROGMEM = "{s}%s US AQI" "{m}%d" "{e}";
const char HTTP_SNS_US_EPA_AQI[] PROGMEM = "{s}%s US EPA AQI" "{m}%d" "{e}";
const char HTTP_SNS_VOLTAGE[] PROGMEM = "{s}" D_VOLTAGE "{m}%s " D_UNIT_VOLT "{e}";
const char HTTP_SNS_CURRENT[] PROGMEM = "{s}" D_CURRENT "{m}%s " D_UNIT_AMPERE "{e}";

View File

@ -353,6 +353,59 @@ void PmsInit(void) {
}
}
// This gives more accurate data for forest fire smoke. PurpleAir gives you this conversion option labeled "US EPA"
// https://cfpub.epa.gov/si/si_public_record_report.cfm?dirEntryId=353088&Lab=CEMM
/*
Copy-paste from the PDF Slide 26
y={0 x <30: 0.524*x - 0.0862*RH + 5.75}
y={30 x <50: (0.786*(x/20 - 3/2) + 0.524*(1 - (x/20 - 3/2)))*x -0.0862*RH + 5.75}
y={50 x <210: 0.786*x - 0.0862*RH + 5.75}
y={210 x <260: (0.69*(x/50 21/5) + 0.786*(1 - (x/50 21/5)))*x - 0.0862*RH*(1 - (x/50 21/5)) + 2.966*(x/50 21/5) + 5.75*(1 - (x/50 21/5)) + 8.84*(10^{-4})*x^{2}*(x/50 21/5)}
y={260 x: 2.966 + 0.69*x + 8.84*10^{-4}*x^2}
y= corrected PM2.5 µg/m3
x= PM2.5 cf_atm (lower)
RH= Relative humidity as measured by the PurpleAir
*/
int usaEpaStandardPm2d5Adjustment(int pm25_standard, int relative_humidity)
{
// Rename to use the same variables from the paper
float x = pm25_standard;
float RH = relative_humidity;
if (x<30) {
return 0.524f * x - 0.0862f * RH + 5.75f;
} else if(x<50) {
return (0.786f * (x/20.0f - 3.0f/2.0f) + 0.524f * (1.0f - (x/20.0f - 3.0f/2.0f))) * x - 0.0862f * RH + 5.75f;
} else if(x<210) {
return 0.786f * x - 0.0862f * RH + 5.75f;
} else if(x<260) {
return (0.69f * (x/50.0f - 21.0f/5.0f) + 0.786f * (1.0f - (x/50.0f - 21.0f/5.0f))) * x - 0.0862f * RH * (1.0f - (x/50.0f - 21.0f/5.0f)) + 2.966f * (x/50.0f - 21.0f/5.0f) + 5.75f * (1.0f - (x/50.0f - 21.0f/5.0f)) + 8.84f * FastPrecisePowf(10.0f, -4.0f) * FastPrecisePowf(x,2.0f) * (x/50.0f - 21.0f/5.0f);
} else {
return 2.966f + 0.69f * x + 8.84f * FastPrecisePowf(10.0f, -4.0f) * FastPrecisePowf(x, 2.0f);
}
}
// Compute US AQI using the 2024+ table
// https://forum.airnowtech.org/t/the-aqi-equation-2024-valid-beginning-may-6th-2024/453
int compute_us_aqi(int pm25_standard)
{
if (pm25_standard <= 9) {
return map_double(pm25_standard, 0, 9, 0, 50);
} else if (pm25_standard <= 35) {
return map_double(pm25_standard, 9.1f, 35.4f, 51, 100);
} else if (pm25_standard <= 55) {
return map_double(pm25_standard, 35.5f, 55.4f, 101, 150);
} else if (pm25_standard <= 125) {
return map_double(pm25_standard, 55.5f, 125.4f, 151, 200);
} else if (pm25_standard <= 225) {
return map_double(pm25_standard, 125.5f, 225.4f, 201, 300);
} else if (pm25_standard <= 325) {
return map_double(pm25_standard, 225.5f, 325.4f, 301, 500);
} else {
return 500;
}
}
void PmsShow(bool json) {
if (Pms.valid) {
char types[10];
@ -370,20 +423,37 @@ void PmsShow(bool json) {
#ifdef PMS_MODEL_PMS5003T
float temperature = ConvertTemp(pms_data.temperature10x/10.0);
float humidity = ConvertHumidity(pms_data.humidity10x/10.0);
int epa_us_aqi;
// When in Fahrenheit include US AQI
if (Settings->flag.temperature_conversion) { // Fahrenheit - US, Liberia, Cayman Islands
epa_us_aqi = compute_us_aqi(usaEpaStandardPm2d5Adjustment(pms_data.pm25_standard, humidity));
}
#endif // PMS_MODEL_PMS5003T
int us_aqi;
// Use US AQI for Fahrenheit, EAQI (European Air Quality Index) for Celsius
if (Settings->flag.temperature_conversion) { // Fahrenheit - US, Liberia, Cayman Islands
us_aqi = compute_us_aqi(pms_data.pm25_standard);
}
if (json) {
ResponseAppend_P(PSTR(",\"%s\":{\"CF1\":%d,\"CF2.5\":%d,\"CF10\":%d,\"PM1\":%d,\"PM2.5\":%d,\"PM10\":%d"),
types,
pms_data.pm10_standard, pms_data.pm25_standard, pms_data.pm100_standard,
pms_data.pm10_env, pms_data.pm25_env, pms_data.pm100_env);
if (Settings->flag.temperature_conversion) { // Fahrenheit - US, Liberia, Cayman Islands
ResponseAppend_P(PSTR(",\"US_AQI\":%d"), us_aqi);
}
#if !(defined(PMS_MODEL_PMS3003) || defined(PMS_MODEL_ZH03X))
ResponseAppend_P(PSTR(",\"PB0.3\":%d,\"PB0.5\":%d,\"PB1\":%d,\"PB2.5\":%d,"),
ResponseAppend_P(PSTR(",\"PB0.3\":%d,\"PB0.5\":%d,\"PB1\":%d,\"PB2.5\":%d"),
pms_data.particles_03um, pms_data.particles_05um, pms_data.particles_10um, pms_data.particles_25um);
#ifdef PMS_MODEL_PMS5003T
ResponseAppend_P(PSTR(","));
ResponseAppendTHD(temperature, humidity);
if (Settings->flag.temperature_conversion) { // Fahrenheit - US, Liberia, Cayman Islands
ResponseAppend_P(PSTR(",\"US_EPA_AQI\":%d"), epa_us_aqi);
}
#else
ResponseAppend_P(PSTR("\"PB5\":%d,\"PB10\":%d"),
ResponseAppend_P(PSTR(",\"PB5\":%d,\"PB10\":%d"),
pms_data.particles_50um, pms_data.particles_100um);
#endif // PMS_MODEL_PMS5003T
#endif // No PMS_MODEL_PMS3003
@ -409,8 +479,14 @@ void PmsShow(bool json) {
WSContentSend_PD(HTTP_SNS_PARTICALS_BEYOND, types, "0.5", pms_data.particles_05um);
WSContentSend_PD(HTTP_SNS_PARTICALS_BEYOND, types, "1", pms_data.particles_10um);
WSContentSend_PD(HTTP_SNS_PARTICALS_BEYOND, types, "2.5", pms_data.particles_25um);
if (Settings->flag.temperature_conversion) { // Fahrenheit - US, Liberia, Cayman Islands
WSContentSend_PD(HTTP_SNS_US_AQI, types, us_aqi);
}
#ifdef PMS_MODEL_PMS5003T
WSContentSend_THD(types, temperature, humidity);
if (Settings->flag.temperature_conversion) { // Fahrenheit - US, Liberia, Cayman Islands
WSContentSend_PD(HTTP_SNS_US_EPA_AQI, types, epa_us_aqi);
}
#else
WSContentSend_PD(HTTP_SNS_PARTICALS_BEYOND, types, "5", pms_data.particles_50um);
WSContentSend_PD(HTTP_SNS_PARTICALS_BEYOND, types, "10", pms_data.particles_100um);
@ -455,4 +531,4 @@ bool Xsns18(uint32_t function)
return result;
}
#endif // USE_PMS5003
#endif // USE_PMS5003