Enhanced the TEMPO satellite data integration to fetch multiple gases (NO2 and O3), estimate AQI from satellite measurements, and display the data in an OpenWeather-compatible format with full health recommendations support.
Location: backend/app/services.py (lines 669-731)
Purpose: Converts TEMPO tropospheric column density measurements to ground-level concentrations and estimates AQI.
Conversion Logic:
- NO2: Converts molecules/m² to μg/m³ using scaling factor
(value / 1e15) * 60 - O3: Converts molecules/m² to μg/m³ using scaling factor
(value / 1e15) * 75 - AQI Estimation: Uses EPA breakpoints to calculate sub-indices for each pollutant
- Final AQI: Returns the maximum of all sub-indices (worst pollutant drives overall AQI)
Returns:
(aqi: int, pollutants: Dict[str, float])
# Example: (3, {'no2': 85.3, 'o3': 75.2, 'pm2_5': 0, 'pm10': 0, 'co': 0, 'so2': 0, 'nh3': 0})Location: backend/app/services.py (lines 734-873)
Purpose: Fetches NO2 and O3 data from TEMPO satellite and formats the response like OpenWeather API.
Key Features:
- Fetches multiple gases (NO2, O3TOT) in parallel
- Handles partial data (continues if one gas fails)
- Estimates AQI and pollutant concentrations
- Returns OpenWeather-compatible format with additional
tempo_detailssection
Response Format:
{
"success": true,
"source": "NASA TEMPO Satellite",
"coordinates": {"lat": 40.7127, "lon": -74.0060},
"data": {
"list": [{
"dt": 1696598400,
"main": {"aqi": 3},
"components": {
"no2": 85.3,
"o3": 75.2,
"pm2_5": 0,
"pm10": 0,
"co": 0,
"so2": 0,
"nh3": 0
}
}]
},
"tempo_details": {
"data_date": "2025-09-16",
"elevation_m": 10.0,
"measurements": {
"NO2": {
"value": 893667669428336.8,
"unit": "molecules/cm²",
"scientific_notation": "8.94e+14"
},
"O3TOT": {
"value": 1.2e+15,
"unit": "molecules/cm²",
"scientific_notation": "1.20e+15"
}
},
"note": "AQI estimated from satellite gas measurements...",
"metadata": {
"satellite": "TEMPO (Tropospheric Emissions: Monitoring of Pollution)",
"coverage_area": "Continental United States",
"temporal_resolution": "Hourly during daylight",
"spatial_resolution": "~2.1 km x 4.4 km"
}
}
}Location: backend/app/routes.py (lines 114-133)
Endpoint: GET /air-pollution/tempo-current
Parameters:
lat(float, required): Latitude coordinatelon(float, required): Longitude coordinatestart_date(string, required): Start date in format YYYY-MM-DDend_date(string, required): End date in format YYYY-MM-DD
Example Request:
GET /air-pollution/tempo-current?lat=40.7127&lon=-74.0060&start_date=2025-09-06&end_date=2025-10-06Location: frontend/src/pages/Index.tsx (lines 80-125)
Changes:
- Switched from
/air-pollution/tempoto/air-pollution/tempo-current - Removed
gasparameter (now fetches multiple gases automatically) - Updated toast messages to mention "NO2 and O3 measurements"
- Check for
tempo_details.data_dateinstead ofdata_date
Location: frontend/src/pages/Index.tsx (lines 721-833)
Features:
- AQI Display: Large AQI number with description and icon (same as OpenWeather)
- Pollutant Cards: Shows NO2 and O3 with "From TEMPO" badge
- Raw Measurements: Collapsible section showing tropospheric column density in scientific notation
- Metadata: Displays satellite info, data date, and elevation
- Satellite Icon: Blue satellite icon to distinguish from OpenWeather data
Visual Example:
╔══════════════════════════════════════╗
║ 🛰️ Estimated AQI from Satellite ║
║ ║
║ 3 ║
║ AQI ║
║ Moderate - Sensitive groups... ║
║ [icon] ║
╠══════════════════════════════════════╣
║ Pollutant Concentrations (μg/m³) ║
║ (Satellite-derived estimates) ║
║ ║
║ ┌────────┐ ┌────────┐ ║
║ │ NO₂ │ │ O₃ │ ║
║ │ 85.3 │ │ 75.2 │ ║
║ │ TEMPO │ │ TEMPO │ ║
║ └────────┘ └────────┘ ║
╠══════════════════════════════════════╣
║ ▶ Raw Satellite Measurements ║
║ (expandable) ║
╠══════════════════════════════════════╣
║ Satellite: NASA TEMPO ║
║ Data Date: 2025-09-16 ║
║ Elevation: 10 m ║
║ Note: AQI estimated from... ║
╚══════════════════════════════════════╝
Location: frontend/src/pages/Index.tsx (lines 863-891)
Changes:
- Unified Data Handling: Both OpenWeather and TEMPO now use
data.list[0]structure - Health Recommendations: TEMPO data now provides health advice (with disclaimer)
- Satellite Badge: Blue info box appears below health recommendations when using TEMPO
- Disclaimer: "AQI estimated from tropospheric column density. Actual ground-level may vary."
Benefits:
- ✅ TEMPO users now get personalized health recommendations
- ✅ LLM-generated advice works with TEMPO data
- ✅ Clear indication that AQI is satellite-estimated
- User selects TEMPO data source → Frontend changes data source to "tempo"
- User selects location → Frontend calls
/air-pollution/tempo-current - Backend searches for data → Searches backwards up to 30 days for available satellite data
- Backend fetches NO2 & O3 → Downloads data from NASA Earthdata
- Backend converts measurements → Converts tropospheric column density to ground-level μg/m³
- Backend estimates AQI → Calculates AQI from converted concentrations
- Backend returns formatted data → Returns OpenWeather-compatible structure
- Frontend displays data → Shows AQI, pollutants, and satellite details
- Health Info works → HealthInfoTab receives AQI and pollutant data like OpenWeather
# 1. Convert NO2 from molecules/m² to μg/m³
no2_ugm3 = (no2_molecules_m2 / 1e15) * 60
# 2. Convert O3 from molecules/m² to μg/m³
o3_ugm3 = (o3_molecules_m2 / 1e15) * 75
# 3. Calculate NO2 AQI sub-index (EPA breakpoints)
if no2_ugm3 <= 53: no2_aqi = 1 # Good
elif no2_ugm3 <= 100: no2_aqi = 2 # Fair
elif no2_ugm3 <= 360: no2_aqi = 3 # Moderate
elif no2_ugm3 <= 649: no2_aqi = 4 # Poor
else: no2_aqi = 5 # Very Poor
# 4. Calculate O3 AQI sub-index
if o3_ugm3 <= 54: o3_aqi = 1 # Good
elif o3_ugm3 <= 70: o3_aqi = 2 # Fair
elif o3_ugm3 <= 85: o3_aqi = 3 # Moderate
elif o3_ugm3 <= 105: o3_aqi = 4 # Poor
else: o3_aqi = 5 # Very Poor
# 5. Overall AQI = worst pollutant
overall_aqi = max(no2_aqi, o3_aqi)| Feature | Status |
|---|---|
| Gases Fetched | NO2 only |
| AQI | ❌ Not available |
| Pollutant Concentrations | ❌ Only raw column density |
| Health Recommendations | ❌ Not available |
| Display Format | Custom satellite display |
| Compatibility | TEMPO-specific |
| Feature | Status |
|---|---|
| Gases Fetched | NO2 + O3 |
| AQI | ✅ Estimated (1-5 scale) |
| Pollutant Concentrations | ✅ Converted to μg/m³ |
| Health Recommendations | ✅ Full support with LLM advice |
| Display Format | OpenWeather-compatible |
| Compatibility | Works with existing components |
# Fetch TEMPO multi-gas data with AQI estimation
curl -X GET "http://localhost:8000/air-pollution/tempo-current?lat=40.7127&lon=-74.0060&start_date=2025-09-06&end_date=2025-10-06"- Select NASA TEMPO as data source
- Search for a US location
- Click "Use My Location" or select from search
- View:
- Estimated AQI with icon
- NO2 and O3 concentrations
- Raw satellite measurements
- Personalized health recommendations
- AQI is estimated from tropospheric column density
- Conversion factors are approximations based on typical atmospheric conditions
- Actual ground-level concentrations may differ
- TEMPO measures vertical column, not surface-level
- More accurate for relative trends than absolute values
📊 TEMPO Data Characteristics:
- Coverage: Continental US only
- Temporal: Hourly during daylight hours
- Processing Delay: 2-3 days typical
- Resolution: ~2.1 km x 4.4 km
- Gases Available: NO2, O3, HCHO (currently using NO2 + O3)
Use TEMPO when:
- ✅ Location is in continental US
- ✅ Need satellite-based measurements
- ✅ Want to see tropospheric column density
- ✅ Interested in spatial patterns across regions
- ✅ OK with 2-3 day data delay
Use OpenWeather when:
- ✅ Need real-time data
- ✅ Location is outside US
- ✅ Want ground-level sensor measurements
- ✅ Need all pollutants (PM2.5, PM10, CO, SO2, etc.)
- ✅ Prefer validated AQI calculations
-
Add HCHO (Formaldehyde)
- Include third gas in multi-gas fetch
- Update AQI estimation with HCHO sub-index
-
Improve Conversion Factors
- Use atmospheric profile data
- Account for seasonal variations
- Consider boundary layer height
-
Validation
- Compare with ground stations when available
- Adjust conversion factors based on validation
-
Historical Trends
- Fetch multiple dates
- Show temporal trends
- Compare with previous weeks/months
-
PM2.5 Estimation
- Research potential PM2.5 proxies from TEMPO
- Explore satellite-based PM estimation
# Start backend
cd backend
python -m uvicorn main:app --reload --host 0.0.0.0 --port 8000
# Test TEMPO multi-gas endpoint
curl -X GET "http://localhost:8000/air-pollution/tempo-current?lat=40.7127&lon=-74.0060&start_date=2025-09-06&end_date=2025-10-06" | jq{
"success": true,
"source": "NASA TEMPO Satellite",
"data": {
"list": [{
"main": {"aqi": 3},
"components": {
"no2": 85.3,
"o3": 75.2,
...
}
}]
},
"tempo_details": {
"measurements": {
"NO2": {...},
"O3TOT": {...}
},
...
}
}✅ TEMPO data is now fully integrated with the rest of the application ✅ Health recommendations work with satellite-estimated AQI ✅ Display format matches OpenWeather for consistency ✅ Users get useful air quality info even with satellite data
The TEMPO satellite data source is now a first-class citizen in the application, providing estimated AQI and health recommendations just like OpenWeather, while maintaining the unique satellite measurement details for users who want to explore the raw data.