demeter

Autonomous Hydroponic Intelligence
commit b100774a44c00249ed7e07e3b1f8a3d38df7ce4a
parent f294d8a2ce498bccf5e8bb516883ab553c0cf2b4
Author: maydayv7 <maydayv7@gmail.com>
Date:   Sat, 28 Mar 2026 15:52:16 +0530

Update README, Help

Diffstat:
Mfrontend/src/pages/Help.jsx | 72++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mfrontend/src/pages/RunCycle.jsx | 28++++++++++++++--------------
Mfrontend/src/utils/translations.js | 16++++++++++++++++
Mreadme.md | 116+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------
4 files changed, 189 insertions(+), 43 deletions(-)

diff --git a/frontend/src/pages/Help.jsx b/frontend/src/pages/Help.jsx @@ -138,6 +138,38 @@ const AI_AGENTS = [ roleKey: "help_agent_explainer_role", detailKey: "help_agent_explainer_detail", }, + { + id: "atmospheric", + icon: Wind, + color: "var(--amber)", + nameKey: "help_agent_atmospheric_name", + roleKey: "help_agent_atmospheric_role", + detailKey: "help_agent_atmospheric_detail", + }, + { + id: "water", + icon: Droplets, + color: "var(--blue)", + nameKey: "help_agent_water_name", + roleKey: "help_agent_water_role", + detailKey: "help_agent_water_detail", + }, + { + id: "supervisor", + icon: Sparkles, + color: "var(--green)", + nameKey: "help_agent_supervisor_name", + roleKey: "help_agent_supervisor_role", + detailKey: "help_agent_supervisor_detail", + }, + { + id: "doctor", + icon: Eye, + color: "var(--red)", + nameKey: "help_agent_doctor_name", + roleKey: "help_agent_doctor_role", + detailKey: "help_agent_doctor_detail", + }, ]; const STAGES = [ @@ -334,6 +366,26 @@ const HELP_EN = { help_agent_explainer_detail: 'After each cycle, this agent writes a human-readable explanation of what happened and why. That\'s what you see in the "AI Decision Reasoning" section of each crop.', + help_agent_atmospheric_name: "Atmospheric Agent", + help_agent_atmospheric_role: "Controls climate and airflow", + help_agent_atmospheric_detail: + "This agent manages fan speed, temperature, and humidity. It calculates Vapor Pressure Deficit (VPD) and adjusts airflow continuously to keep the growing environment in the optimal range for the crop type and current growth stage.", + + help_agent_water_name: "Water Agent", + help_agent_water_role: "Manages nutrient solution and pH", + help_agent_water_detail: + "This agent calculates the precise dosage of acid, base, and nutrient solution needed to correct pH and EC levels. It uses a physics-based model of the water tank to predict how much dosing is required, then refines it with what the RL agent has learned from past cycles.", + + help_agent_supervisor_name: "Supervisor Agent", + help_agent_supervisor_role: "Merges plans and sends final commands", + help_agent_supervisor_detail: + "The supervisor combines the plans from the Atmospheric and Water agents, validates them against the Strategy agent's recommendation, and dispatches the final actuator commands to the hardware. It is the last AI step before any physical action is taken.", + + help_agent_doctor_name: "Doctor Agent", + help_agent_doctor_role: "Diagnoses plant health visually", + help_agent_doctor_detail: + "Using computer vision (Azure CV), this agent analyzes the plant image uploaded during each cycle to detect disease, pest damage, or visual anomalies. Its diagnosis is attached to the cycle log and can trigger critical alerts even when sensor readings appear normal.", + // Growth Stages help_stage_seedling: "Seedling", help_stage_seedling_desc: @@ -530,6 +582,26 @@ const HELP_HI = { help_agent_explainer_detail: 'प्रत्येक cycle के बाद, यह agent एक human-readable explanation लिखता है कि क्या हुआ और क्यों। यही आप हर फसल की "AI निर्णय तर्क" section में देखते हैं।', + help_agent_atmospheric_name: "वायुमंडलीय एजेंट", + help_agent_atmospheric_role: "जलवायु और वायु प्रवाह नियंत्रित करता है", + help_agent_atmospheric_detail: + "यह एजेंट पंखे की गति, तापमान और नमी को नियंत्रित करता है। यह VPD (Vapor Pressure Deficit) की गणना करता है और हर फसल और विकास अवस्था के लिए वातावरण को सही रखने के लिए वायु प्रवाह को लगातार समायोजित करता है।", + + help_agent_water_name: "जल एजेंट", + help_agent_water_role: "पोषक घोल और pH को नियंत्रित करता है", + help_agent_water_detail: + "यह एजेंट pH और EC स्तर को सुधारने के लिए एसिड, बेस और पोषक घोल की सटीक मात्रा की गणना करता है। यह पानी के टैंक के भौतिक मॉडल का उपयोग करके अनुमान लगाता है कि कितनी dosing आवश्यक है, और RL एजेंट के पिछले cycles से सीखे गए अनुभव से इसे बेहतर करता है।", + + help_agent_supervisor_name: "सुपरवाइज़र एजेंट", + help_agent_supervisor_role: "योजनाओं को जोड़ता है और अंतिम कमांड भेजता है", + help_agent_supervisor_detail: + "सुपरवाइज़र वायुमंडलीय और जल एजेंटों की योजनाओं को मिलाता है, उन्हें Strategy एजेंट की सिफारिश के साथ जांचता है, और हार्डवेयर को अंतिम एक्चुएटर कमांड भेजता है। कोई भी शारीरिक कार्रवाई से पहले यह अंतिम AI चरण है।", + + help_agent_doctor_name: "डॉक्टर एजेंट", + help_agent_doctor_role: "दृश्य रूप से पौधे के स्वास्थ्य का निदान करता है", + help_agent_doctor_detail: + "Computer Vision (Azure CV) का उपयोग करके, यह एजेंट हर चक्र में अपलोड की गई पौधे की तस्वीर का विश्लेषण करता है और बीमारी, कीट क्षति या दृश्य असामान्यताओं का पता लगाता है। इसका निदान चक्र लॉग में जोड़ा जाता है और तब भी अलर्ट ट्रिगर कर सकता है जब सेंसर रीडिंग सामान्य लगती हैं।", + // Stages help_stage_seedling: "अंकुर (Seedling)", help_stage_seedling_desc: diff --git a/frontend/src/pages/RunCycle.jsx b/frontend/src/pages/RunCycle.jsx @@ -415,7 +415,7 @@ export default function RunCycle() { color: "var(--text-3)", }} > - Loading crop… + {t("run_loading_crop")} </span> </div> </PageShell> @@ -483,7 +483,10 @@ export default function RunCycle() { fontWeight: 600, }} > - {cycles} cycle{cycles !== 1 ? "s" : ""} completed + {t("run_cycles_complete", { + n: cycles, + s: cycles !== 1 ? "s" : "", + })} </span> </div> )} @@ -578,8 +581,8 @@ export default function RunCycle() { }} > {daysLeft === 0 - ? "✂ Ready to harvest" - : `${daysLeft}d until harvest`} + ? t("run_harvest_ready") + : t("run_days_until", { n: daysLeft })} </span> )} </div> @@ -601,7 +604,7 @@ export default function RunCycle() { color: "var(--text-3)", }} > - Growth Progress + {t("run_growth_progress")} </span> <span style={{ @@ -1006,11 +1009,8 @@ export default function RunCycle() { > <div style={{ display: "flex", alignItems: "center", gap: 8 }}> <div className="section-label"> - {phase === "running" - ? "🔴 Live Agent Feed" - : phase === "done" - ? "✅ Cycle Log" - : "Agent Log"} + phase === "running" ? t("add_log_live") : phase === "done" ? + t("add_log_done") : t("add_log_idle") </div> {phase === "running" && ( <span @@ -1026,7 +1026,7 @@ export default function RunCycle() { alignSelf: "center", }} > - STREAMING + {t("run_streaming")} </span> )} </div> @@ -1062,7 +1062,7 @@ export default function RunCycle() { fontSize: 11, }} > - Waiting for agent output… + {t("run_log_waiting")} </div> ) : ( logs.map((entry, i) => ( @@ -1125,12 +1125,12 @@ export default function RunCycle() { {phase === "running" ? ( <> <Brain size={18} style={{ animation: "pulse 1s infinite" }} /> - Agents Working… + {t("run_agents_working")} </> ) : phase === "done" ? ( <> <RotateCcw size={17} /> - Run Another Cycle + {t("add_run_another")} </> ) : ( <> diff --git a/frontend/src/utils/translations.js b/frontend/src/utils/translations.js @@ -201,6 +201,14 @@ const en = { run_title: "Run Agent Cycle", run_subtitle: "Execute AI monitoring cycle for {crop}", run_for_crop: "Running for: {crop}", + run_loading_crop: "Loading crop…", + run_growth_progress: "Growth Progress", + run_streaming: "STREAMING", + run_log_waiting: "Waiting for agent output…", + run_cycles_complete: "{n} cycle{s} completed", + run_agents_working: "Agents Working…", + run_harvest_ready: "✂ Ready to harvest", + run_days_until: "{n}d until harvest", // Alerts alerts_title: "Alerts", @@ -680,6 +688,14 @@ const hi = { run_title: "एजेंट चक्र चलाएं", run_subtitle: "{crop} के लिए AI चक्र चलाएं", run_for_crop: "फसल: {crop} के लिए", + run_loading_crop: "फसल लोड हो रही है…", + run_growth_progress: "विकास प्रगति", + run_streaming: "लाइव", + run_log_waiting: "एजेंट आउटपुट की प्रतीक्षा…", + run_cycles_complete: "{n} चक्र पूरे हुए", + run_agents_working: "एजेंट काम कर रहे हैं…", + run_harvest_ready: "✂ कटाई के लिए तैयार", + run_days_until: "कटाई में {n} दिन बाकी", // Alerts alerts_title: "अलर्ट", diff --git a/readme.md b/readme.md @@ -39,13 +39,13 @@ Built for the **Microsoft AI Unlocked - AI for India** hackathon, Demeter addres - `Knowledge_Base` - agronomic research documents (RAG) - `Plant_Biographies_HF` - long-term per-crop memory (via Mem0) - **Mem0** - semantic plant biography system backed by Azure OpenAI -- **NodeJS + MongoDB** - structured crop metadata and event logs +- **MongoDB** - primary structured store for crop state, sensor history, and simulator state ### Physics Simulator -- **Digital Twin** with a hybrid physics + neural residual model -- Simulates pH, EC, water temp, air temp, humidity, VPD, and biomass -- Exposes REST API consumed by both the agent loop and frontend +- **Multi-batch Digital Twin**: FastAPI server that manages one `DigitalTwin` instance per crop, all loaded into memory and synced from MongoDB on every request +- Simulates pH, EC, water temp, air temp, humidity, VPD, and biomass across all active crops simultaneously +- Hybrid physics + neural residual model (`ResidualPhysicsNet`) and image generation - Syncs state to **Azure Digital Twins** after every action --- @@ -160,37 +160,84 @@ The JudgeAgent is the reward signal generator. After each cycle, it: 6. **Updates Qdrant** payload and **writes to FarmMemory (Mem0)** 7. Returns training data → Bandit updates its weights online -### The Simulator - Physics + Neural Residual Digital Twin +### The Simulator - Multi-Batch Physics + Neural Residual Digital Twin -The simulator (`simulator/main.py`) is a **FastAPI server** running a `DigitalTwin` class: +The simulator (`simulator/main.py`) is a **FastAPI server** managing a **fleet of `DigitalTwin` instances** — one per active crop: +- **Multi-batch architecture**: An in-memory `simulators` dict maps `crop_id → DigitalTwin`. On every request, `sync_simulators_from_db()` reads MongoDB and instantiates twins for any newly registered crops automatically - **Hybrid physics model**: First-principles equations for pH, EC, VPD, biomass growth - **Neural residual**: A small `ResidualPhysicsNet` (PyTorch MLP) that corrects physics approximations - **State vector**: `[pH, EC, water_temp, air_temp, humidity, VPD, biomass]` +- **Global clock**: A `simulator_state` MongoDB collection tracks the global tick; each `GET /simulation/state` call advances it by 1 hour and increments `simulated_age_hours` for every crop - **Image generation**: Outputs plant health images based on a bucket score (0–100) - **Azure Digital Twins sync**: Every action call pushes telemetry to the ADT twin (`HydrophonicTank`) -- **Dual endpoints**: `/simulation/state` (agent loop) and `/azure/state` (ADT read-back) +- **Endpoints**: + - `GET /simulation/state` — returns state for **all** active crops + - `POST /simulation/action` — accepts a **list** of `{crop_id, action}` objects, steps each twin --- ## Frontend -The frontend is a highly responsive React 19 SPA featuring bilingual support (English/हिन्दी) for accessibility in Indian agriculture, made to serve as a Proof-of-Concept. +The frontend is a highly responsive React 19 SPA featuring bilingual support (English/हिन्दी) for accessibility in Indian agriculture. ### Pages -| Page | Route | Description | -| ----------------- | --------------- | -------------------------------------------------------------------------------------------------- | -| Landing Page | `/` | Hero, live agent activity feed, feature cards, live stats | -| Dashboard | `/dashboard` | Crop card grid with health/maturity/stage filters and harvest banner | -| Crop Details | `/crop/:id` | Per-crop sensor charts, agent reasoning log, event timeline, actuator commands | -| Add Crop | `/add-crop` | Form to initialize a crop + live agent pipeline log with 6-phase progress tracker | -| Add Crop | `/add-crop` | Form to initialize a crop + live agent pipeline log with 6-phase progress tracker | -| Farm Intelligence | `/intelligence` | Natural-language RAG search against the agronomic knowledge base | -| Analytics | `/analytics` | Multi-chart analytics: pH/EC/temp traces, daily sequences, parameter health scores, per-crop table | -| Alerts | `/alerts` | Categorized alert system (CRITICAL/WARNING/INFO/HARVEST) with acknowledge workflow | -| Help | `/help` | Farming terms, Simple explanations and definitions | -| Settings | `/settings` | Theme, language, farm name, notification prefs, onboarding | +| Page | Route | Description | +| ----------------- | -------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- | +| Landing Page | `/` | Hero, live agent activity feed, feature cards, live stats | +| Dashboard | `/dashboard` | Crop card grid with health/maturity/stage filters and harvest banner | +| Crop Details | `/crop/:id` | Per-crop sensor charts, agent reasoning log, event timeline, actuator commands | +| Add Crop | `/add-crop` | Crop registration form: Type, ID, location, notes, sensor IDs, and optional seed photo | +| Run Cycle | `/run-cycle/:cropId` | Triggers agent cycle for a specific crop. Streams live logs with phase progress indicator, live sensor readout panel, and actuator command summary | +| Farm Intelligence | `/intelligence` | Natural-language RAG search against the agronomic knowledge base | +| Analytics | `/analytics` | Multi-chart analytics: pH/EC/temp traces, daily sequences, parameter health scores, per-crop table | +| Alerts | `/alerts` | Categorized alert system (CRITICAL/WARNING/INFO/HARVEST) with acknowledge workflow | +| Help | `/help` | Farming terms, simple explanations and definitions | +| Settings | `/settings` | Theme, language, farm name, notification prefs, onboarding | + +--- + +## Backend + +The Node.js Express server (`backend/node_server/`) is the **primary CRUD layer** for all crop data, backed by MongoDB. + +### Crop Schema + +``` +crop_id String (unique, required) +crop String +stage String +sequence_number Number +cycle_duration_hours Number (auto-set per crop type: lettuce/basil=1h, tomato/strawberry=2h) +total_crop_lifetime_days Number +simulated_age_hours Number +planted_at Date +last_updated Date +sensors { pH: [Number], EC: [Number], temp: [Number], humidity: [Number] } +sensor_ids { ph_sensor, ec_sensor, temp_sensor, humidity_sensor } +location String +notes String +image_url String +action_taken Mixed +outcome String +explanation_log String +bandit_action_id Number +strategic_intent String +reward_score Number +visual_diagnosis String +schema_version String (current: "1.2") +``` + +### API Routes + +| Method | Path | Description | +| ------ | -------------------- | ----------------------- | +| POST | `/api/crops/create` | Register a new crop | +| GET | `/api/crops/all` | Retrieve all crops | +| GET | `/api/crops/:cropId` | Get a single crop by ID | +| PUT | `/api/crops/:cropId` | Partial update | +| DELETE | `/api/crops/:cropId` | Remove a crop | --- @@ -246,24 +293,32 @@ demeter/ │ │ ├── create-index.py # Qdrant index setup script │ │ └── reset-db.py # Database reset utility │ └── node_server/ -│ ├── index.js # Express.js server - crop CRUD API -│ ├── routes/farmRoutes.js # Farm route definitions -│ ├── controllers/ # Farm controller logic -│ └── config/db.js # MongoDB connection +│ ├── index.js # Express.js server - crop CRUD API + MongoDB init +│ ├── routes/ +│ │ ├── farmRoutes.js # Farm/Qdrant history routes +│ │ └── cropRoutes.js # Crop CRUD routes +│ ├── controllers/ +│ │ ├── farmController.js +│ │ └── cropController.js +│ ├── schema/ +│ │ └── cropSchema.js # Mongoose schema (v1.2) +│ └── config/db.js # MongoDB + legacy DB connection │ ├── frontend/ │ ├── src/ │ │ ├── App.js # Router, providers, onboarding gate -│ │ ├── pages/ # All 8 page components +│ │ ├── pages/ # All 10 page components │ │ ├── components/ # Sidebar, AgentWidgets, Onboarding │ │ ├── hooks/ # useFarmData, useSettings, useTranslation -│ │ ├── api/ # agentApi.js, farmApi.jsx +│ │ ├── api/ +│ │ │ ├── agentApi.js +│ │ │ └── farmApi.jsx # MongoDB CRUD calls │ │ ├── utils/ # translations.js, dataUtils.js │ │ └── data/mockData.js # Mock data for testing │ └── tailwind.config.js │ ├── simulator/ -│ └── main.py # DigitalTwin + FastAPI server + Azure ADT sync +│ └── main.py # Multi-batch DigitalTwin fleet + Azure ADT sync │ ├── Knowledge_Base/ # Drop agronomic PDFs here for RAG ingestion ├── requirements.txt @@ -280,6 +335,7 @@ demeter/ - NodeJS 18+ - A running [Qdrant](https://qdrant.tech/) instance (local Docker or Qdrant Cloud) - Azure OpenAI resource with GPT-4.1 deployment +- MongoDB instance (local or Atlas) - (Optional) Azure Digital Twins instance ### 1. Clone & Install Python Dependencies @@ -324,7 +380,7 @@ ADT_URL=your-adt-instance.digitaltwins.azure.net # Backend PORT=3001 -MONGODB_URI=your_mongodb_url +MONGODB_URI=your_mongodb_connection_string # Frontend REACT_APP_AGENT_API_URL=http://localhost:8000 @@ -346,12 +402,14 @@ docker run -p 6333:6333 -p 6334:6334 qdrant/qdrant ### 4. Initialize Database -Run the following command from the root directory to create the required collections and indexes: +Run the following command from the root directory to create the required Qdrant collections and indexes: ```bash python backend/server/create-index.py ``` +MongoDB collections are created automatically on first use by the simulator. + ### 5. Initialize the Knowledge Base (RAG) Place agronomic PDFs in the `Knowledge_Base/` folder, then run: