OnAir Usage

How to post data

Send a POST to https://emms.margpharma.com/api/readings with HTTP Basic Auth using the sensor-writer credentials and a JSON body.


    

Fields

id (station) and timestamp (ISO 8601) are required. All metrics are numeric and optional; values may be sent as numbers or strings.

FieldMetricUnit

How the AQI is calculated

The AQI shown on the Real-Time and Dashboard pages is computed client-side following the U.S. EPA Technical Assistance Document for the Reporting of Daily Air Quality (May 2026 edition, EPA‑403/B‑26‑003). It mirrors the method behind the live AirNow map, so our values line up with what AirNow reports for the same concentrations.

The index

Each pollutant gets a sub-index from its measured concentration using the EPA piecewise-linear equation (Equation 1):

I = (I_hi − I_lo) / (C_hi − C_lo) × (C − C_lo) + I_lo

where C is the concentration and the C_lo / C_hi / I_lo / I_hi values are the breakpoints that bracket it (Table 6 of the document). The overall AQI is the maximum of all pollutant sub-indices; the pollutant that produced it is the "dominant" pollutant. See AQI Basics and the interactive AQI Calculator.

Pollutants and units

Breakpoints are defined in EPA's native units. Our sensor reports gases in µg/m³, so those are converted to ppm/ppb before indexing using the ideal-gas relation at EPA reference conditions (25 °C, 1 atm): ppb = µg/m³ × 24.45 / MW. Because the conversion assumes reference temperature and pressure, the gas sub-indices are approximate; the particulates (measured directly) are usually dominant.

PollutantAveraging / basisBreakpoint unitSource value
pm25 PM2.512-hour NowCastµg/m³µg/m³ (direct)
pm10 PM1012-hour NowCastµg/m³µg/m³ (direct)
o3 O₃max of 8-hour & 1-hourppmµg/m³ → ppm
co CO8-hourppmµg/m³ → ppm
so2 SO₂1-hourppbµg/m³ → ppb
no2 NO₂1-hourppbµg/m³ → ppb

Note — CO unit mismatch. The field reference labels co (and co2) as ppm, but the production data shows CO values are actually in µg/m³ (a median around 600 and peaks over 4000, which are only physically plausible as µg/m³ — as ppm they would be far past lethal). The AQI treats co as µg/m³ and converts it, which is correct for this data. The ppm label in the schema is likely wrong and should be reconciled; co2 is not an AQI pollutant, so its label does not affect the index.

PM NowCast

PM2.5 and PM10 are run through EPA's 12-hour NowCast rather than a single instantaneous reading, so the real-time number responds quickly when air quality changes (for example during smoke) while staying stable when it does not. The weight factor is 1 − (max − min) / max over the last 12 hourly values, clamped to [0.5, 1]; recent hours are weighted more heavily. This matches how AirNow reports hourly PM.

Missing data

The sensor uses sentinel values for channels it cannot read: PM reports -1 and a gas channel that is absent reports 0. These are treated as missing rather than real concentrations — missing PM hours are skipped by the NowCast, and a gas with no reading is left out of the AQI instead of scoring a misleading "Good" sub-index or becoming the dominant pollutant.

Categories

The sub-index value maps to one of six categories (Table 1 of the document):

Values above 500 are not clamped: per Table 6 footnote 4, Equation 1 keeps being applied using the concentration anchored to an AQI of 500, so extreme readings can report above 500.

References