AWS Builder Center
CoolRoof: Turning Satellite Heat Data into and Solar Decisions for Indian Cities, on AWS

CoolRoof: Turning Satellite Heat Data into and Solar Decisions for Indian Cities, on AWS

How we built CoolRoof Planner for the Environmental Hacks "Heat and Water" track: Landsat surface temperature ranked by ward and roof, a PM subsidy-fund rooftop-solar assessment, and a Hindi/English agent on Amazon Bedrock, running on AWS serverless.

Developing Scalable Software and Working on Edge AI
Built for Environmental Hacks (WeMakeDevs x AWS, Bharat Builds Tour), Heat and Water track. Repo: [ LINK ]

The problem: cities know it's hot, but not where to act

Every summer, Indian cities get hotter, and municipal planners are asked where cool-roof and cooling programmes should go first. Usually they have no ward-level data to answer that. Meanwhile a homeowner who qualifies for the PM Surya Ghar rooftop-solar subsidy faces a confusing application process, with no guidance that is specific to their locality.
We built CoolRoof Planner + SuryaCheck to cover both ends. Planners get a ranked list of wards and buildings. Homeowners get a plain-language solar assessment, in Hindi or English.

What we built

For a given city with ward boundaries, the system:
  1. Computes hot-season Land Surface Temperature (LST) from Landsat 8/9.
  1. Joins it with building footprints and population data.
  1. Ranks wards, then buildings, for cool-roof intervention using explicit, configurable scoring.
  1. Runs SuryaCheck: roof area, system size, PM Surya Ghar subsidy, and a payback range.
  1. Offers a bilingual Hindi/English agent that explains the results and produces a downloadable PDF.
  1. Shows everything on a React map dashboard.

Five rules we refused to break

Before writing code, we set rules for the whole build. They shaped everything else.
  • No invented values. Every coefficient, price and threshold comes from config or a cited source.
  • Missing data is  unavailable , never  0 . A silent zero looks like a real answer. An explicit "unavailable" doesn't.
  • The LLM never computes numbers. All numbers come from deterministic functions. The agent only explains tool outputs.
  • Ranges, not points, for anything scenario-based, such as cool-roof impact, generation and payback.
  • Honest wording. LST is "surface temperature at a late-morning satellite pass", not air temperature. Heat drivers are "associated with", never "caused by".

Architecture on AWS

The AWS target is serverless, with no Kubernetes:
  • Amazon S3 holds raw rasters, curated feature tables, map tiles and generated PDFs. Landsat is read straight from the USGS requester-pays bucket.
  • AWS Step Functions + Lambda run the batch heat pipeline: STAC search, windowed raster reads, QA masking, zonal statistics and ward scoring.
  • Amazon DynamoDB stores the ward context, roof context, policy records and agent sessions.
  • Amazon API Gateway + Lambda serve a FastAPI backend (via Mangum) with a pydantic-generated OpenAPI spec.
  • Amazon Bedrock + the Strands Agents SDK power the bilingual agent. Its tools are the deterministic APIs.
  • AWS Amplify hosts the React + MapLibre frontend.
  • AWS CDK (Python) defines the stacks, and CloudWatch handles monitoring.


Local-first, same code

Every external dependency sits behind an interface with a  local  and an  aws  implementation, selected by one environment variable:
Bash
RUNTIME=local # S3 -> ./data, DynamoDB -> SQLite, Bedrock -> mock/Anthropic
RUNTIME=aws # S3, DynamoDB, Bedrock
The whole prototype runs with  make dev  on a laptop with no AWS credentials. That made it possible to build and test quickly during a short hackathon, and then deploy the same code to AWS.

From satellite pixels to a ranked ward list

Land surface temperature. We use the USGS Landsat Collection 2 Level-2 surface temperature product, mask clouds, shadows and snow using the QA band, and read scale and offset from the STAC metadata instead of hardcoding them. We composite the hot-season scenes into a median LST.
Heat island. We subtract a rural reference median to get ΔLST, compute area-weighted stats per ward, and measure persistence: how often a ward sits in the city's hottest decile.

Ward priority score. Each ward gets a transparent score built from five components: heat, persistence, exposed population, lack of green cover, and roof opportunity.
Plain text
Need = (a_H·H + a_P·P + a_E·E + a_V·V) / Σa
Priority = Need · (0.5 + 0.5·R) · F
To avoid false precision, we run a Dirichlet weight-sensitivity analysis (1,000 draws). So each ward shows a rank interval and a top-10 stability figure, not just a single rank.

Roofs. Landsat's thermal band is about 100 m native resolution, so we cannot read an individual roof's temperature. Roof ranking therefore uses neighbourhood heat, roof area, people protected and cost, ordered by benefit per rupee. Cool-roof coefficients are scenario ranges, flagged as placeholders until calibrated by a real pilot.

SuryaCheck: subsidy, size and payback

SuryaCheck chains location, solar resource, roof suitability, system size, subsidy, and net-metering payback. The subsidy rule is policy-as-data, so a policy change means a data update, not a deploy:
Plain text
Residential: S(c) = 30000·min(c,2) + 18000·max(0, min(c,3) − 2)
That gives ₹30,000 for 1 kW, ₹60,000 for 2 kW, and ₹78,000 for 3 kW and above. We test this against table fixtures.
Payback is the part where honesty matters most. Tariffs and net-metering terms are set per state, with no national table. So if we don't have a verified, fresh tariff for the user's DISCOM, we return a status like  payback_unavailable_no_tariff  instead of guessing. The orchestrator returns  complete  or  partial , along with what is missing and the next questions to ask.


A Hindi/English agent that can't make up numbers

The agent, built with Strands on Bedrock, handles language detection (including Hinglish) and calls typed tools: ward context, solar assessment, subsidy rules, checklist and PDF generation.
The key idea is the grounding check. After the model drafts a reply, we extract every number in it, in Latin or Devanagari digits, with ₹/Rs and lakh/crore, and verify each one appears in that session's tool outputs. If a number can't be traced, we regenerate once and then fall back to a template. The result: the LLM explains, and the deterministic code does the arithmetic.
The same discipline applies to the PDF, which is rendered with Jinja2 and WeasyPrint using Noto Sans and Noto Sans Devanagari. Every number in it traces back to the assessment.


The dashboard

The React + Vite + MapLibre frontend, with PMTiles for map layers and i18next for Hindi/English, shows:
  • the ward heat map, with the LST disclaimer shown next to it;
  • ward ranking with component bars, rank interval and confidence;
  • ranked roofs and cool-roof impact ranges;
  • the SuryaCheck card, agent chat and PDF download.
Every number carries a class badge and, on hover, its source, date and resolution. An unavailable value shows the reason instead of a blank.

What We learned

  1. Constraints written down on day one beat heroics on day three. The "never invent a value" rule saved us from many small, plausible-looking mistakes.
  1. Local-first is a hackathon superpower. Not waiting on credentials or cloud deploys let us iterate quickly.
  1. Ranges communicate honesty. Showing a payback or impact range feels less impressive in a demo, but it is more trustworthy.
  1. Let the LLM do language, not maths. Separating explanation from calculation made the agent testable.

What's next

Cool-roof coefficients and costs are placeholders until a 10 to 20 roof pilot calibrates them. We'd like to add real DISCOM tariff records, and more of the planned heat-intelligence layer: heat-type classification, driver attribution, a heat-dome forecast signal, and fire and habitat-pressure alerts.

Try it

  • Track: Heat and Water, Environmental Hacks (WeMakeDevs x AWS)
Thanks to WeMakeDevs and AWS for the event. Landsat data courtesy of the U.S. Geological Survey.
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