@@ -353,6 +353,59 @@ void PmsInit(void) {
353
353
}
354
354
}
355
355
356
+ // This gives more accurate data for forest fire smoke. PurpleAir gives you this conversion option labeled "US EPA"
357
+ // https://cfpub.epa.gov/si/si_public_record_report.cfm?dirEntryId=353088&Lab=CEMM
358
+ /*
359
+ Copy-paste from the PDF Slide 26
360
+ y={0 ≤ x <30: 0.524*x - 0.0862*RH + 5.75}
361
+ y={30≤ x <50: (0.786*(x/20 - 3/2) + 0.524*(1 - (x/20 - 3/2)))*x -0.0862*RH + 5.75}
362
+ y={50 ≤ x <210: 0.786*x - 0.0862*RH + 5.75}
363
+ 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)}
364
+ y={260 ≤ x: 2.966 + 0.69*x + 8.84*10^{-4}*x^2}
365
+
366
+ y= corrected PM2.5 µg/m3
367
+ x= PM2.5 cf_atm (lower)
368
+ RH= Relative humidity as measured by the PurpleAir
369
+ */
370
+ int usaEpaStandardPm2d5Adjustment (int pm25_standard, int relative_humidity)
371
+ {
372
+ // Rename to use the same variables from the paper
373
+ float x = pm25_standard;
374
+ float RH = relative_humidity;
375
+ if (x<30 ) {
376
+ return 0 .524f * x - 0 .0862f * RH + 5 .75f ;
377
+ } else if (x<50 ) {
378
+ 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 ;
379
+ } else if (x<210 ) {
380
+ return 0 .786f * x - 0 .0862f * RH + 5 .75f ;
381
+ } else if (x<260 ) {
382
+ 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 );
383
+ } else {
384
+ return 2 .966f + 0 .69f * x + 8 .84f * FastPrecisePowf (10 .0f , -4 .0f ) * FastPrecisePowf (x, 2 .0f );
385
+ }
386
+ }
387
+
388
+ // Compute US AQI using the 2024+ table
389
+ // https://forum.airnowtech.org/t/the-aqi-equation-2024-valid-beginning-may-6th-2024/453
390
+ int compute_us_aqi (int pm25_standard)
391
+ {
392
+ if (pm25_standard <= 9 ) {
393
+ return map_double (pm25_standard, 0 , 9 , 0 , 50 );
394
+ } else if (pm25_standard <= 35 ) {
395
+ return map_double (pm25_standard, 9 .1f , 35 .4f , 51 , 100 );
396
+ } else if (pm25_standard <= 55 ) {
397
+ return map_double (pm25_standard, 35 .5f , 55 .4f , 101 , 150 );
398
+ } else if (pm25_standard <= 125 ) {
399
+ return map_double (pm25_standard, 55 .5f , 125 .4f , 151 , 200 );
400
+ } else if (pm25_standard <= 225 ) {
401
+ return map_double (pm25_standard, 125 .5f , 225 .4f , 201 , 300 );
402
+ } else if (pm25_standard <= 325 ) {
403
+ return map_double (pm25_standard, 225 .5f , 325 .4f , 301 , 500 );
404
+ } else {
405
+ return 500 ;
406
+ }
407
+ }
408
+
356
409
void PmsShow (bool json) {
357
410
if (Pms.valid ) {
358
411
char types[10 ];
@@ -370,20 +423,37 @@ void PmsShow(bool json) {
370
423
#ifdef PMS_MODEL_PMS5003T
371
424
float temperature = ConvertTemp (pms_data.temperature10x /10.0 );
372
425
float humidity = ConvertHumidity (pms_data.humidity10x /10.0 );
426
+ int epa_us_aqi;
427
+ // When in Fahrenheit include US AQI
428
+ if (Settings->flag .temperature_conversion ) { // Fahrenheit - US, Liberia, Cayman Islands
429
+ epa_us_aqi = compute_us_aqi (usaEpaStandardPm2d5Adjustment (pms_data.pm25_standard , humidity));
430
+ }
373
431
#endif // PMS_MODEL_PMS5003T
432
+ int us_aqi;
433
+ // Use US AQI for Fahrenheit, EAQI (European Air Quality Index) for Celsius
434
+ if (Settings->flag .temperature_conversion ) { // Fahrenheit - US, Liberia, Cayman Islands
435
+ us_aqi = compute_us_aqi (pms_data.pm25_standard );
436
+ }
374
437
375
438
if (json) {
376
439
ResponseAppend_P (PSTR (" ,\" %s\" :{\" CF1\" :%d,\" CF2.5\" :%d,\" CF10\" :%d,\" PM1\" :%d,\" PM2.5\" :%d,\" PM10\" :%d" ),
377
440
types,
378
441
pms_data.pm10_standard , pms_data.pm25_standard , pms_data.pm100_standard ,
379
442
pms_data.pm10_env , pms_data.pm25_env , pms_data.pm100_env );
443
+ if (Settings->flag .temperature_conversion ) { // Fahrenheit - US, Liberia, Cayman Islands
444
+ ResponseAppend_P (PSTR (" ,\" US_AQI\" :%d" ), us_aqi);
445
+ }
380
446
#if !(defined(PMS_MODEL_PMS3003) || defined(PMS_MODEL_ZH03X))
381
- ResponseAppend_P (PSTR (" ,\" PB0.3\" :%d,\" PB0.5\" :%d,\" PB1\" :%d,\" PB2.5\" :%d, " ),
447
+ ResponseAppend_P (PSTR (" ,\" PB0.3\" :%d,\" PB0.5\" :%d,\" PB1\" :%d,\" PB2.5\" :%d" ),
382
448
pms_data.particles_03um , pms_data.particles_05um , pms_data.particles_10um , pms_data.particles_25um );
383
449
#ifdef PMS_MODEL_PMS5003T
450
+ ResponseAppend_P (PSTR (" ," ));
384
451
ResponseAppendTHD (temperature, humidity);
452
+ if (Settings->flag .temperature_conversion ) { // Fahrenheit - US, Liberia, Cayman Islands
453
+ ResponseAppend_P (PSTR (" ,\" US_EPA_AQI\" :%d" ), epa_us_aqi);
454
+ }
385
455
#else
386
- ResponseAppend_P (PSTR (" \" PB5\" :%d,\" PB10\" :%d" ),
456
+ ResponseAppend_P (PSTR (" , \" PB5\" :%d,\" PB10\" :%d" ),
387
457
pms_data.particles_50um , pms_data.particles_100um );
388
458
#endif // PMS_MODEL_PMS5003T
389
459
#endif // No PMS_MODEL_PMS3003
@@ -409,8 +479,14 @@ void PmsShow(bool json) {
409
479
WSContentSend_PD (HTTP_SNS_PARTICALS_BEYOND, types, " 0.5" , pms_data.particles_05um );
410
480
WSContentSend_PD (HTTP_SNS_PARTICALS_BEYOND, types, " 1" , pms_data.particles_10um );
411
481
WSContentSend_PD (HTTP_SNS_PARTICALS_BEYOND, types, " 2.5" , pms_data.particles_25um );
482
+ if (Settings->flag .temperature_conversion ) { // Fahrenheit - US, Liberia, Cayman Islands
483
+ WSContentSend_PD (HTTP_SNS_US_AQI, types, us_aqi);
484
+ }
412
485
#ifdef PMS_MODEL_PMS5003T
413
486
WSContentSend_THD (types, temperature, humidity);
487
+ if (Settings->flag .temperature_conversion ) { // Fahrenheit - US, Liberia, Cayman Islands
488
+ WSContentSend_PD (HTTP_SNS_US_EPA_AQI, types, epa_us_aqi);
489
+ }
414
490
#else
415
491
WSContentSend_PD (HTTP_SNS_PARTICALS_BEYOND, types, " 5" , pms_data.particles_50um );
416
492
WSContentSend_PD (HTTP_SNS_PARTICALS_BEYOND, types, " 10" , pms_data.particles_100um );
@@ -455,4 +531,4 @@ bool Xsns18(uint32_t function)
455
531
return result;
456
532
}
457
533
458
- #endif // USE_PMS5003
534
+ #endif // USE_PMS5003
0 commit comments