AgriPulse

Inspiration

Every hackathon has a "farming AI" project. Almost all of them are the same idea wearing a different UI: point a model at a leaf photo, get a disease name back.

It looks impressive in a demo and solves almost nothing, because the real bottleneck for a farmer was never "what's wrong with this leaf." It's a decision they make every single morning with incomplete information:

Should I irrigate today?

The stats made the problem impossible to ignore.

Agriculture accounts for roughly 72% of global freshwater withdrawals (FAO AQUASTAT, 2025), and global irrigation efficiency sits around 56% - meaning almost half of all water applied to fields never even reaches the crop (FAO AQUASTAT).

Meanwhile, agrifood systems are responsible for about a third of global greenhouse gas emissions (FAO, 2025), and the UN projects the population hitting 9.7 billion by 2050, piling more demand onto the same water.

None of that gets fixed by an app that tells you your tomato has blight.

It gets fixed, even a little, by helping someone decide not to run their pump when it isn't necessary.

That's the whole idea AgriPulse is built around.


What It Does

A farmer enters four things:

  1. Crop
  2. Planting date
  3. Farm location
  4. Area

AgriPulse turns that into one daily recommendation:

  • Irrigate
  • Wait
  • Inspect

The reasoning is shown alongside the recommendation, not hidden behind a black box.

Under the hood, it runs two independent engines and combines them.

Engine 1 - Water Demand

We calculate crop evapotranspiration using the real FAO Penman-Monteith relationship:

ETc = Kc × ET₀

ET₀ (reference evapotranspiration) comes from live weather data:

  • Temperature
  • Humidity
  • Wind
  • Radiation

Kc (crop coefficient) is not a weather variable. It's looked up from an agronomic crop-stage table based on:

  • Crop
  • Days since planting

Multiply them and you get modeled daily water demand.

For example:

ET₀ = 4.8 mm
Kc = 1.15

ETc = 4.8 × 1.15
    ≈ 5.5 mm/day

We then run a simplified soil-water balance:

SoilWater(t) =
    SoilWater(t−1)
    + Rain
    + Irrigation
    − ETc
    − Drainage

This produces an estimated status:

  • LOW
  • MODERATE
  • ADEQUATE

We deliberately don't present a fake precise number, because without a physical soil sensor, claiming exact soil moisture would just be a lie with decimals.


Engine 2 - Is the Crop Actually Growing Normally?

We pull Sentinel-2 satellite imagery and compute NDVI over the farm's actual polygon, not a single pixel.

The calculation is:

NDVI = (NIR − Red) / (NIR + Red)

Instead of simply showing:

NDVI = 0.51

and calling it a day, we compare it against the expected NDVI trajectory for that crop at that growth stage.

For example, if a rice field is 50 days in and should be around 0.65 but is actually at 0.51:

Deviation = (0.65 − 0.51) / 0.65
          ≈ 22%

We flag that for a field inspection.

We deliberately don't diagnose a cause - disease, pests, water, nutrients - from that number alone.

NDVI genuinely can't tell you the cause by itself, and pretending it can is how these tools lose trust.


Decision Engine

Both engines feed into a decision engine, and only then does an LLM get involved.

The LLM is used purely to translate the structured output into plain language that a farmer can act on.

It:

  • Never calculates anything
  • Never fills in a missing measurement
  • Never invents sensor or satellite data

If satellite data is unavailable because of cloud cover, the system says exactly that instead of guessing.


How We Built It

Frontend

  • Next.js
  • React
  • TypeScript
  • Tailwind CSS

Backend

  • Python
  • FastAPI
  • Pydantic

Database

  • PostgreSQL
  • PostGIS for storing farm polygons and geographic queries

Data Science

  • NumPy
  • Pandas
  • GeoPandas
  • Rasterio

Used for raster and satellite-band processing.

Weather

  • Live current conditions
  • Forecast data
  • Historical baseline data

Used for:

  • ET₀ calculation
  • Rainfall modeling

Satellite

  • Sentinel-2 imagery
  • ESA Copernicus data
  • Red/NIR bands
  • NDVI computation

AI Layer

An LLM is called only at the final explanation step.

It receives a structured JSON field state object - never raw sensor data - and is never asked to perform calculations.

Infrastructure

  • Docker
  • Environment-based secrets
  • Deployed for the live demo

AI Philosophy

We treated the AI like a narrator, not an engineer.

Everything upstream of it is deterministic code:

  • Kc lookup
  • Penman-Monteith
  • Water balance
  • NDVI computation
  • Anomaly detection

The system produces the same number every time you run it.

That was a conscious design choice.


Challenges We Ran Into

Getting Kc Values Right

Getting crop coefficient values right without requiring a farmer to manually enter them was harder than expected.

Crop coefficients change through distinct growth stages:

  • Initial
  • Development
  • Mid-season
  • Late-season

So we had to build a lookup table keyed on:

Crop type + Days since planting

rather than using one fixed value.


Cloud Cover on Sentinel-2

Cloud cover on Sentinel-2 scenes was a real, recurring problem - not an edge case we invented for the "honesty" slide.

Some fields simply had no clean recent image.

That forced us to actually build the fallback path:

Confidence: LOW
Satellite: UNAVAILABLE

instead of assuming clean satellite imagery would always be available.


Combining Independent Signals

Combining two genuinely independent signals without letting one silently override the other took real iteration.

Our two signals were:

  1. Physics-based water model
  2. Satellite NDVI/vigor signal

Early versions leaned too heavily on NDVI and started making INSPECT-heavy recommendations that weren't backed by the water balance.

We had to make the decision engine properly account for both signals.


Accomplishments We're Proud Of

We Kept the AI Honest

It would have been faster to simply prompt an LLM with:

"Here's some weather and satellite data. Tell the farmer what to do."

And it would have looked almost identical in a five-minute demo.

We didn't do that.

Every number the farmer sees is labeled as:

  • Measured
  • Calculated
  • Estimated
  • Predicted

The system also actively says:

"I don't know."

when it doesn't know, instead of quietly inventing a plausible-sounding answer.


We Got Both Engines Working End-to-End

We managed to get both major pipelines working:

  • The agronomic water model
  • The satellite NDVI pipeline

And, more importantly, we got them talking to each other.

That was the part we were most worried about not finishing within the hackathon.


What We Learned

The hard part of agri-tech isn't finding data sources.

Weather APIs and Sentinel-2 are free and well documented.

The hard part is resisting the urge to let a language model paper over uncertainty.

It's genuinely tempting to let the AI "fill in the blank" when data is missing because it makes the product feel smarter.

We learned that's exactly the thing that makes these tools untrustworthy in practice.

A clear limitation is more valuable to a farmer than a confident-sounding guess.


What's Next for AgriPulse

Soil Sensors

Replace the estimated water-balance status with real measured soil moisture.

Nutrient Management

Layer nutrient recommendations on top of:

  • Soil tests
  • Crop stage
  • Field conditions

Not guessed from NDVI alone.

Pest & Disease Risk Modeling

Combine:

  • Weather
  • Crop stage
  • Satellite trends
  • Farmer-submitted field photos

But frame the output as risk, not diagnosis.

Climate Resilience Monitoring

Monitor:

  • Drought
  • Heat stress
  • Flood risk

Using the same historical-baseline comparison approach.

Farm Economics

Fold in:

  • Irrigation cost
  • Energy cost
  • Commodity prices

So recommendations account for what a decision actually costs, not just what the crop needs.


The Goal

The goal isn't to build "an AI for farming."

It's to build the decision layer that turns data farmers already have access to into one thing they can trust enough to act on.

AgriPulse - helping farmers decide when not to irrigate.

Built With

Share this project:

Updates

Submission history