AWS Builder Center
DownWind: Estimating Where Crop-Residue Smoke Will Travel, Built Serverless on AWS

DownWind: Estimating Where Crop-Residue Smoke Will Travel, Built Serverless on AWS

DownWind uses NASA satellite data on fire locations and predicts the travel of smoke on a wind forecast to predict which North Indian cities will be affected by the smoke, and sends out an email to interested parties as a heads-up. Here is how I built it with AWS Lambda, EventBridge, DynamoDB, API Gateway, SNS, Amplify, Systems Manager and AWS SAM.

The problem

Every year, crop-residue burning in Punjab and Haryana produces smoke heading towards the cities of North India. But satellite fire data is available to the public, so how would we turn that into a simple, honest estimate for the people asking "will it reach my city and when" and let them subscribe for an email alert?

What it does

  • Shows fire detections from NASA FIRMS, as clusters on a map, sized by intensity
  • Estimates which cities are downwind of the clusters, and how far and when smoke might arrive
  • Lets people subscribe to an email alert for a city (confirmed by email first, with unsubscribe link)
  • Documents sources and limitations on a Method page

Estimate details

Every 30 minutes a pipeline runs:
  1. Gets fire detections from NASA FIRMS, filtering out low confidence
  1. Keeps only those in Punjab and Haryana (using a boundary polygon)
  1. Groups those into grid clusters (count, total fire radiative power, centroid)
  1. Gets wind speed and direction from Open-Meteo (on a coarse grid)
  1. Computes the smoke direction, because wind direction is where the wind comes from, the smoke travels towards (direction + 180) % 360
  1. Checks for each city, is it in a corridor around that direction, and within reach of the cluster, and if so estimates the time to arrival as distance / wind speed
  1. Combines the clusters affecting a city into a High, Medium or Low severity
  1. If severity is High and the city hasn't been alerted recently, sends an alert
One easy thing to do wrong is to average wind directions, because the average of 350 and 10 degrees is 0, not 180. This is why the pipeline uses a circular mean.
This is a heuristic estimate, not a smoke dispersion model. The corridor angle and reach and severity thresholds are initial values that have not been validated against ground measurements, and the site says they're indicative.

Architecture

plaintext
EventBridge (every 30 min)
|
v
Lambda: ingest --> NASA FIRMS + Open-Meteo --> impact calculation
|
v
DynamoDB (clusters, impact, geocode cache)
^ |
| v
API Gateway --> Lambda: API SNS (per-city email topics)
^
|
Amplify Hosting (React website)
CloudWatch: logs and alarms
Systems Manager Parameter Store: NASA FIRMS key

How I used AWS

AWS open source
  • AWS SAM CLI: the whole backend is one  template.yaml . I'll validate it with  sam validate --lint , package it with  sam build  and create the stack with  sam deploy , so the infrastructure is reproducible from the repository.
AWS services
  • AWS Lambda (Python 3.12): one function for the ingest pipeline and one for the API.
  • Amazon EventBridge: triggers the ingest function on a schedule.
  • Amazon DynamoDB: stores clusters, city impact and a reverse-geocoding cache in on-demand with TTL (old data expires).
  • Amazon API Gateway (HTTP API): the public API, with throttling and CORS restricted to website's own domain.
  • Amazon SNS: one email topic per city. Subscriptions use SNS's confirmation flow, so nobody is subscribed without confirmation, and every email carries an unsubscribe link.
  • AWS Amplify Hosting: builds and hosts the React website from GitHub.
  • AWS Systems Manager Parameter Store: stores the NASA FIRMS key as a SecureString, so it's never in the code, repository or browser bundle.
  • Amazon CloudWatch: logs, plus alarms for ingest errors and API failures.
  • AWS CloudFormation and IAM: SAM deploys through CloudFormation, and each function gets its own least-privilege role.

Design decisions worth sharing

  • No subscribers table. SNS handles confirmation, unsubscribing and delivery, so I've let it be the source of truth.
  • No duplicate alerts. The ingest function run can happen before the previous run's data has changed. A conditional DynamoDB update decides who sends the alert, and a cooldown prevents the same city being alerted multiple times.
  • The API key is in Parameter Store. CloudFormation cannot create SecureString parameters, so that one step is done by hand in the console.
  • Only the services the design needed. I did not use Cognito (no accounts), S3 (no uploads) or OpenSearch (no search).

Limits, stated plainly

  • Satellites detect heat anomalies. A detection is not confirmed crop-residue burning.
  • There is a delay between a fire and its detection, so the data is near real time, not real time.
  • Air quality figures on the site are modelled estimates, not station readings.
  • The smoke path and severity are indicative estimates.

What I would do next

  • Validate the estimate against ground air quality stations
  • Add SMS or WhatsApp alerts
  • Add village-level alerts

Data and credits

Fire data: NASA FIRMS. Wind and air quality: Open-Meteo. Map: OpenStreetMap contributors. Administrative boundaries courtesy of geoBoundaries.org.
Any opinions in this article are those of the individual author and may not reflect the opinions of AWS.
Enjoyed reading this content? Let the author know!

Your likes, comments, shares, and saves help creators reach more builders.

Loading recommendations

Loading article