Skip to content

Repository files navigation

🌱 C3 Smart Agriculture Backend

Backend for the Smart Agriculture Platform — Group C3 (System Engineering & Interaction)

This is the BFF (Backend For Frontend) that connects the farmer-facing React dashboard to C1's IoT sensors (via Kafka), C2's AI/ML models (via REST), and C4's infrastructure (via Keycloak + Prometheus).


What does this backend do?

C1 Sensors (ESP32)          C2 AI Models (FastAPI)
       │                            │
   [Kafka]                     [HTTP/REST]
       │                            │
       ▼                            ▼
┌──────────────────────────────────────────┐
│         C3 FastAPI Backend               │
│                                          │
│  • Consumes sensor data from Kafka       │
│  • Proxies AI predictions from C2        │
│  • Pushes live data via Socket.IO        │
│  • Exposes REST API for the dashboard    │
│  • Serves Prometheus metrics for C4      │
└──────────────────────────────────────────┘
       │                            │
   [Socket.IO]                 [REST API]
       │                            │
       ▼                            ▼
              React Dashboard
         (agri-dashboard frontend)

It does not store its own data — C2 owns the database (PostgreSQL + InfluxDB). This backend is a pass-through layer that translates, aggregates, and streams data between the frontend and the other subgroups.


Tech stack

Technology Purpose
FastAPI Web framework — handles REST endpoints
aiokafka Kafka consumer — receives C1 sensor data asynchronously
python-socketio WebSocket server — pushes live data to the React frontend
httpx Async HTTP client — calls C2's FastAPI endpoints
pydantic-settings Config management — reads .env file
prometheus-fastapi-instrumentator Metrics — auto-exposes /metrics for C4's Prometheus
uvicorn ASGI server — runs the FastAPI app

Project structure

c3-backend/
│
├── .env                        ← Your secrets (git-ignored)
├── .env.example                ← Template for teammates
├── .gitignore
├── Dockerfile                  ← For C4 to containerise
├── requirements.txt            ← Python dependencies
│
├── venv/                       ← Virtual environment (do not edit)
│
└── app/
    ├── __init__.py
    ├── main.py                 ← Entry point — starts everything
    │
    ├── config/
    │   ├── __init__.py
    │   └── settings.py         ← Reads .env, exports settings object
    │
    ├── middleware/
    │   ├── __init__.py
    │   └── auth.py             ← Mock auth now, Keycloak later
    │
    ├── models/
    │   ├── __init__.py
    │   ├── sensor.py           ← KafkaMessage + ZoneState schemas
    │   └── irrigation.py       ← IrrigationZone + TriggerRequest schemas
    │
    ├── routes/
    │   ├── __init__.py
    │   ├── sensors.py          ← GET /api/sensors
    │   ├── irrigation.py       ← GET/POST /api/irrigation/*
    │   ├── analytics.py        ← GET /api/analytics/yield, /soil-forecast
    │   ├── weather.py          ← GET /api/weather/forecast (Open-Meteo)
    │   ├── alerts.py           ← GET /api/alerts/anomalies
    │   ├── growth.py           ← GET /api/growth/stage
    │   ├── water_stress.py     ← GET /api/water-stress
    │   └── satellite.py        ← GET /api/satellite/ndvi
    │
    └── services/
        ├── __init__.py
        ├── kafka_consumer.py   ← Consumes C1 sensor data, aggregates by zone
        ├── socket_service.py   ← Pushes live data to React via Socket.IO
        └── c2_proxy.py         ← HTTP calls to C2's FastAPI

Getting started

Prerequisites

  • Python 3.11+
  • pip
  • A code editor (VS Code recommended)

Setup

# 1. Clone the repo
git clone https://github.com/AgriSenseNet/agri-backend.git
cd agri-backend

# 2. Create and activate virtual environment
python3 -m venv venv
source venv/bin/activate        # macOS/Linux
# venv\Scripts\activate         # Windows

# 3. Install dependencies
pip install -r requirements.txt

# 4. Create your .env file
cp .env.example .env
# Edit .env with your actual values

# 5. Start the server
uvicorn app.main:app --reload --port 3001

Verify it works

URL Expected
http://localhost:3001/health {"status": "ok"}
http://localhost:3001/docs Swagger UI (interactive API docs)
http://localhost:3001/metrics Prometheus metrics text
http://localhost:3001/api/sensors {"count": 0, "zones": []}
http://localhost:3001/api/irrigation/zones 4 mock irrigation zones

API endpoints

Sensor data (from C1 via Kafka)

Method Path Description
GET /api/sensors All zones with latest aggregated readings
GET /api/sensors/{zone_id} One specific zone

Irrigation

Method Path Description
GET /api/irrigation/zones All irrigation zones
POST /api/irrigation/trigger Toggle irrigation on/off
POST /api/irrigation/recommendation AI recommendation from C2

Analytics (proxied from C2)

Method Path Description
GET /api/analytics/yield Crop yield prediction
GET /api/analytics/soil-forecast Soil moisture forecast (24–72h)

Weather

Method Path Description
GET /api/weather/forecast 5-day forecast from Open-Meteo

Alerts

Method Path Description
GET /api/alerts/anomalies Sensor anomaly detections from C2

Growth & water (from C2)

Method Path Description
GET /api/growth/stage Crop growth stage classification
GET /api/water-stress Evapotranspiration & water stress index
GET /api/satellite/ndvi NDVI satellite vegetation data

Infrastructure

Method Path Description
GET /health Kubernetes health check
GET /metrics Prometheus metrics

How data flows

Live Kafka data (C1 → Dashboard)

C1 ESP32 sensors and bridge
    → MQTT bridge topics
    → Kafka topics: "iot-sensors", "iot-device-status", "iot-logs"
    → C3 aiokafka consumer (kafka_consumer.py)
    → Aggregates sensor telemetry into zone_states dict
    → Stores latest device availability per zone and recent log events
    → python-socketio broadcasts sensor/device/log updates
    → React frontend receives live data via socket.io-client

Sensor telemetry messages contain one sensor reading for one zone:

{"zone": "zone1", "sensor": "soil_moisture", "value": 42, "unit": "%", "ts": 1746172800000}

The consumer aggregates these into a complete zone object:

{"zone": "zone1", "soil_moisture": 42, "temperature": 24.5, "humidity": 55, ...}

Device availability messages arrive on iot-device-status:

{"zone": "zone2", "status": "online", "ts": 1746172800000}

Log events arrive on iot-logs:

{"zone": "zone1", "ts": 1746172800, "type": "system", "msg": "pump restarted"}

AI predictions (Dashboard → C2)

React frontend
    → C3 FastAPI route (e.g. /api/analytics/yield)
    → c2_proxy.py calls C2's FastAPI (e.g. /predict/yield)
    → Response forwarded back to frontend

Environment variables

Variable Default Description
PORT 3001 Server port
FRONTEND_URL http://localhost:5173 React app URL (for CORS)
KAFKA_BROKER kafka.cropwise.garden:9095 Kafka broker bootstrap servers
KAFKA_TOPIC iot-sensors Backward-compatible alias for the sensor topic
KAFKA_SENSOR_TOPIC iot-sensors Sensor telemetry Kafka topic
KAFKA_DEVICE_STATUS_TOPIC iot-device-status Device availability Kafka topic
KAFKA_LOGS_TOPIC iot-logs Log/event Kafka topic
KAFKA_GROUP_ID c3-dashboard-group Consumer group name
C2_API_URL http://localhost:8000 C2's FastAPI base URL
AUTH_MODE mock mock or keycloak

Integration with other subgroups

C1 — Device & Edge Systems

  • Connection: Kafka consumer on topics iot-sensors, iot-device-status, and iot-logs
  • Broker: kafka.cropwise.garden:9095
  • Message format: Sensor telemetry, device availability, and bridge log events
  • Our consumer group: c3-dashboard-group

C2 — Data & Intelligence

  • Connection: HTTP calls via httpx.AsyncClient
  • 6 ML model endpoints + 1 satellite CR endpoint
  • Note: C2 endpoints have no /api prefix (e.g. /predict/yield not /api/predict/yield)
  • Weather: C2 does not expose weather — C3 calls Open-Meteo directly

C4 — Platform, Security & Integration

  • Deployment: Docker container on Kubernetes (port 3001)
  • Auth: Keycloak OIDC (mock mode for development)
  • Monitoring: Prometheus scrapes /metrics
  • Health: Kubernetes probes hit /health
  • WebSocket: Socket.IO on /socket.io path — Kong must allow WebSocket upgrade

Running with the frontend

Open two terminals:

Terminal 1 — Backend

cd c3-backend
source venv/bin/activate
uvicorn app.main:app --reload --port 3001

Terminal 2 — Frontend

cd agri-dashboard
npm run dev

Open http://localhost:5173 in your browser.


Docker

# Build
docker build -t c3-backend .

# Run
docker run -p 3001:3001 --env-file .env c3-backend

Troubleshooting

Error Fix
ModuleNotFoundError: No module named 'app' Run uvicorn from the c3-backend/ folder, not inside app/
ModuleNotFoundError: No module named 'fastapi' Activate your venv: source venv/bin/activate
Address already in use Another process on port 3001. Kill it or change PORT in .env
[Kafka] Failed to connect Kafka broker not reachable — REST endpoints still work
CORS error in browser FRONTEND_URL in .env must match your Vite dev URL exactly
422 Unprocessable Entity Request body doesn't match the Pydantic model — check /docs
502 C2 error C2's FastAPI is not running or unreachable

Daily Workflow

Before starting work, always pull latest

git pull origin main

# Create a branch for your feature
git checkout -b feat/kafka-ssl-config

# Do your work, then commit
git add .
git commit -m "feat: add SSL config for Kafka port 9094"

# Push your branch
git push origin feat/kafka-ssl-config

# Then open a Pull Request on GitHub to merge into main

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages