CropCore is a desktop analytics pipeline for farm field monitoring. It ingests field boundaries, pulls remote satellite and weather data, runs agronomic analysis, and exports per-field and farm-level reports — all from a single command.
Built for dryland Prairie Canada (Alberta / Saskatchewan / Manitoba). No subscription required for weather or elevation data. Satellite imagery requires a free Copernicus CDSE account.
- Fetches NDVI from Sentinel-2 (Copernicus CDSE), elevation/slope from CDEM or SRTM, and weather from Open-Meteo
- Runs all API calls concurrently via
ThreadPoolExecutor - Computes per-field NDVI stats, stress index, review priority, yield forecast (wheat/barley/canola), and growing-season trend
- Exports per-field and farm-level PDF, HTML, and text reports, plus a field-summary CSV and QGIS layer manifest
- Optional soil overlay (local GPKG/SHP or Alberta Open Data REST — no API key)
- Optional post-run email summary via SMTP
- Interactive console UI with Ctrl+C cancellation, or run headless with
--sd-path
- Python 3.11 or newer
- Copernicus CDSE account (free) — for Sentinel-2 NDVI imagery
- All other data sources (weather, elevation, Alberta soils) are free and require no account
# 1. Clone the repository
git clone https://github.com/YOUR_USERNAME/CropCore.git
cd CropCore
# 2. Create and activate a virtual environment
python3 -m venv .venv
source .venv/bin/activate
# 3. Install dependencies
pip install -r requirements.txt
# 4. Set up your API credentials
cp config/config.example.json config/config.json
# Edit config/config.json — add your Copernicus CDSE client ID and secret# 1. Clone the repository
git clone https://github.com/YOUR_USERNAME/CropCore.git
cd CropCore
# 2. Create and activate a virtual environment
python -m venv .venv
.venv\Scripts\activate
# 3. Install dependencies
pip install -r requirements.txt
# 4. Set up your API credentials
copy config\config.example.json config\config.json
# Edit config\config.json — add your Copernicus CDSE client ID and secretSee the User Manual for a full step-by-step walkthrough including how to create field boundaries in QGIS.
# Run with the console UI (guided)
python run.py
# Or run directly against your data folder
python run.py --sd-path data --debug
# Or use the helper script
chmod +x run.sh && ./run.shREM Run with the console UI (guided)
python run.py
REM Or run directly against your data folder
python run.py --sd-path data --debug
REM Or double-click run.bat in File ExplorerOutputs are written to:
| Path | Contents |
|---|---|
data/out/reports/ |
PDFs, HTML reports, text summaries, CSV, weather chart |
data/out/rasters/ |
Clipped NDVI and slope GeoTIFFs |
data/out/gif/ |
NDVI time-lapse GIF (when enabled) |
data/logs/ |
run.log |
Place your field data under data/in/ before running:
data/
in/
boundaries/ <- put boundaries.gpkg or boundaries.shp here (required)
soil/ <- optional soil polygons (GPKG / SHP / GeoJSON)
machine_logs.csv <- optional machine log data
config/
job_config.json <- per-run settings (dates, which APIs to call, alerts)
Don't have a boundaries file yet? See the QGIS boundary guide in the user manual. A sample boundary is auto-generated on first run if none is found.
The data/ directory is gitignored — your field data stays local.
Copy config/config.example.json to config/config.json and fill in:
| Key | Description |
|---|---|
sentinelhub_client_id |
Copernicus CDSE OAuth client ID |
sentinelhub_client_secret |
Copernicus CDSE OAuth client secret |
cdem_api_key |
Optional — leave empty to use the free SRTM fallback |
soil_layer_path_or_url |
Optional — path or URL to a soil layer; leave empty to auto-use Alberta Open Data |
email_summary |
Optional SMTP settings for a post-run summary email |
Do not commit config/config.json — it is gitignored.
Controls what each run does. Key fields:
| Field | Description |
|---|---|
name |
Job label used in report filenames |
analysis_level |
"field", "farm", or "both" |
start_date / end_date |
Date range for imagery and weather (YYYY-MM-DD) |
apis.sentinel |
Enable/disable Sentinel-2 NDVI fetch |
apis.cdem |
Enable/disable elevation/slope fetch |
outputs.compute_ndvi_trend |
Enable monthly NDVI trend analysis |
alerts.ndvi_min |
Flag fields with mean NDVI below this value |
alerts.dry_streak_days_max |
Flag when dry streak exceeds this many days |
alerts.stress_index_max |
Flag when stress index exceeds this (0-100) |
See data/config/job_config.example.json for a fully annotated example.
The boundaries.gpkg (or .shp) file supports two optional columns:
| Column | Effect |
|---|---|
name |
Human-readable field name shown in all reports |
crop_type |
Crop label (e.g. Wheat, Canola, Barley) — enables crop-grouped farm summary and yield forecasting |
When crop_type is set to a supported crop, CropCore estimates yield using a peak-NDVI linear regression calibrated for Prairie dryland conditions:
| Crop labels recognised | Model | Typical range |
|---|---|---|
Wheat, Spring Wheat, Durum, CWRS, CPS |
Spring Wheat | ~20-65 bu/ac |
Barley, Malt Barley, Feed Barley |
Barley | ~25-75 bu/ac |
Canola, Rapeseed, Oilseed Rape |
Canola | ~15-45 bu/ac |
Penalty adjustments are applied for dry streaks and within-field NDVI variability. A soil drainage modifier is applied automatically when a soil overlay is present. Results appear in per-field reports, farm overview, and the CSV with a plus/minus 20% confidence interval.
Literature basis: Mkhabela et al. (2011), Potgieter et al. (2017), Peng et al. (2018), Zhong et al. (2019).
Two transparent, rule-based scores (no ML) appear in every report:
- Stress index (0-100): overall stress likelihood from NDVI, variability, slope, and trend — labelled Low / Moderate / High
- Review priority (0-100): urgency to scout a field, used to sort the farm overview's "Suggested review" list
Soil polygons can be provided three ways (in priority order):
- Place a GPKG/SHP/GeoJSON under
data/in/soil/ordata/in/soils/ - Set
soil_layer_path_or_urlinconfig/config.json - Leave both empty — CropCore queries the Alberta Open Data Soil Groups layer automatically (no API key required)
CropCore computes area-weighted dominant soil unit, texture, and drainage class per field, and feeds the drainage class into the yield model.
python -m pytest tests -v187 tests covering job config, validation, alerts, APIs, HTML reports, yield forecasting, and a full pipeline smoke test.
- User Manual — full installation, QGIS boundary setup, configuration reference, and output guide (Linux + Windows)
- Operator Quick-Start — one-page printable reference card
