ESPHome 2026.3.0-dev
Loading...
Searching...
No Matches
aqi_calculator.h
Go to the documentation of this file.
1#pragma once
2
3#include <algorithm>
4#include <cmath>
5#include <limits>
7
8// https://document.airnow.gov/technical-assistance-document-for-the-reporting-of-daily-air-quailty.pdf
9
10namespace esphome::aqi {
11
13 public:
14 uint16_t get_aqi(float pm2_5_value, float pm10_0_value) override {
15 float pm2_5_index = calculate_index(pm2_5_value, PM2_5_GRID);
16 float pm10_0_index = calculate_index(pm10_0_value, PM10_0_GRID);
17
18 float aqi = std::max(pm2_5_index, pm10_0_index);
19 if (aqi < 0.0f) {
20 aqi = 0.0f;
21 }
22 return static_cast<uint16_t>(std::lround(aqi));
23 }
24
25 protected:
26 static constexpr int NUM_LEVELS = 6;
27
28 static constexpr int INDEX_GRID[NUM_LEVELS][2] = {{0, 50}, {51, 100}, {101, 150}, {151, 200}, {201, 300}, {301, 500}};
29
30 static constexpr float PM2_5_GRID[NUM_LEVELS][2] = {
31 // clang-format off
32 {0.0f, 9.1f},
33 {9.1f, 35.5f},
34 {35.5f, 55.5f},
35 {55.5f, 125.5f},
36 {125.5f, 225.5f},
37 {225.5f, std::numeric_limits<float>::max()}
38 // clang-format on
39 };
40
41 static constexpr float PM10_0_GRID[NUM_LEVELS][2] = {
42 // clang-format off
43 {0.0f, 55.0f},
44 {55.0f, 155.0f},
45 {155.0f, 255.0f},
46 {255.0f, 355.0f},
47 {355.0f, 425.0f},
48 {425.0f, std::numeric_limits<float>::max()}
49 // clang-format on
50 };
51
52 static float calculate_index(float value, const float array[NUM_LEVELS][2]) {
53 int grid_index = get_grid_index(value, array);
54 if (grid_index == -1) {
55 return -1.0f;
56 }
57 float aqi_lo = INDEX_GRID[grid_index][0];
58 float aqi_hi = INDEX_GRID[grid_index][1];
59 float conc_lo = array[grid_index][0];
60 float conc_hi = array[grid_index][1];
61
62 return (value - conc_lo) * (aqi_hi - aqi_lo) / (conc_hi - conc_lo) + aqi_lo;
63 }
64
65 static int get_grid_index(float value, const float array[NUM_LEVELS][2]) {
66 for (int i = 0; i < NUM_LEVELS; i++) {
67 const bool in_range =
68 (value >= array[i][0]) && ((i == NUM_LEVELS - 1) ? (value <= array[i][1]) // last bucket inclusive
69 : (value < array[i][1])); // others exclusive on hi
70 if (in_range) {
71 return i;
72 }
73 }
74 return -1;
75 }
76};
77
78} // namespace esphome::aqi
static constexpr float PM2_5_GRID[NUM_LEVELS][2]
static constexpr int NUM_LEVELS
static int get_grid_index(float value, const float array[NUM_LEVELS][2])
static float calculate_index(float value, const float array[NUM_LEVELS][2])
static constexpr float PM10_0_GRID[NUM_LEVELS][2]
static constexpr int INDEX_GRID[NUM_LEVELS][2]
uint16_t get_aqi(float pm2_5_value, float pm10_0_value) override