api / CLAUDE.md
safraeli's picture
Deploy: 2026 sensor migration + redesign + bucket B endpoints
13fc29d verified
|
Raw History Blame Contribute Delete
9.48 kB
# CLAUDE.md
## Project Overview
**SolarWine** β€” Photosynthesis prediction and tracker control system for an agrivoltaic vineyard (*Vitis vinifera*) in Sde Boker, Israel.
Two-stage pipeline:
1. **Stage 1 (Mechanistic)**: Farquhar et al. (1980) model driven by on-site sensors (PAR, leaf temp, COβ‚‚, VPD) β†’ net photosynthesis rate *A* (Β΅mol COβ‚‚/mΒ²/s)
2. **Stage 2 (ML)**: IMS weather station data β†’ predict *A* without on-site sensors, enabling day-ahead forecasting
## Repository Layout
```
backend/ FastAPI REST API (routes, auth, workers)
config/ settings.py (paths, IMS channels, panel geometry)
context/ Project docs, todo, code review notes
frontend/ React + TypeScript + Vite SPA
scripts/ CLI tools (data download, pipeline, training)
src/ Core Python modules
advisor/ Day-ahead advisory engine
chatbot/ LLM integration (Google Gemini)
data/ IMS client, ThingsBoard client, DataHub
forecasting/ ML predictors, time-series, Chronos wrapper
models/ Farquhar model, phenology
shading/ Solar geometry, tracker optimizer
tracker/ Tracker optimization module
ui/ Streamlit UI utilities
app.py Legacy Streamlit dashboard
```
## Tech Stack
**Backend**: Python 3.12, FastAPI, uvicorn, pydantic, PyJWT, slowapi, sentry-sdk
**ML/Science**: pandas, numpy, scikit-learn, xgboost, pvlib, scipy, torch, chronos-forecasting (HuggingFace)
**LLM**: google-genai (Gemini)
**Frontend**: React 18, TypeScript 5, Vite 5, Tailwind CSS, shadcn/ui, Recharts, TanStack React Query, React Router 6
**Data sources**: IMS API (station 43, Sde Boker), ThingsBoard (MQTT/REST), on-site sensors
**Deploy**: HuggingFace Spaces (backend, port 7860), Cloudflare Pages (frontend), Streamlit Community Cloud (legacy)
## Environment Setup
```bash
# Python (from repo root)
python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
pip install -r backend/requirements.txt
# Frontend
cd frontend && npm install
```
Required `.env` variables:
```
IMS_API_TOKEN=<token>
JWT_SECRET=<secret>
ADMIN_PASSWORD=<password>
# Optional
SENTRY_DSN=<dsn>
ALLOWED_ORIGINS=http://localhost:5173,https://solarwine.pages.dev
```
## Common Commands
### Backend
```bash
# Dev server (auto-reload)
uvicorn backend.api.main:app --reload --port 7860
# Production
uvicorn backend.api.main:app --host 0.0.0.0 --port 7860
```
### Frontend
```bash
cd frontend
npm run dev # Vite dev server β†’ http://localhost:5173
npm run build # Production build β†’ dist/
npm run lint # ESLint
npm run test # Vitest
npm run test:watch # Watch mode
```
### Legacy Streamlit
```bash
streamlit run app.py
```
### Data & Pipelines
```bash
# Download IMS weather data
python -m scripts.download_ims_data --from 2024-01-01 --to 2025-12-31
# Full Stage 1 β†’ Stage 2 pipeline
python -m scripts.run_pipeline
# Fine-tune Chronos (long-context forecasting)
python scripts/run_chronos_long_training.py --device cpu --context-days 28 --num-steps 4000
# Generate trimmed sample CSV for cloud deploy
python -m scripts.create_sample_data
# Control system simulation / validation
python -m scripts.run_control_simulation
python -m scripts.verify_control_system
# Budget audit (compliance report)
python -m src.budget_audit --report # weekly rollup
python -m src.budget_audit --daily 2026-03-29 # single day
# Load test (requires: pip install locust)
locust -f scripts/load_test.py --host https://solarwine-api.hf.space \
--users 10 --spawn-rate 2 --run-time 5m --headless
```
## Architecture Notes
### Backend (FastAPI)
- **`DataHub`** (`src/data/data_providers.py`) β€” singleton facade over all providers; injected via `backend/api/deps.py`
- **Routes** (`backend/api/routes/`): `health`, `weather`, `sensors`, `energy`, `photosynthesis`, `control`, `chatbot`, `biology`, `login`, `events` (~27 endpoints)
- **Auth**: JWT issued at `/api/auth/login`; guest read-only mode when `JWT_SECRET` unset
- **Middleware**: CORS, rate-limiting (60 req/min via slowapi), request logging, global exception handler β†’ JSON errors
- **Workers** (`backend/workers/`): async background tasks for daily planner and control ticks
- **Services** (`backend/services/`): `DataFlowMonitor` (per-source health), `EmailAlerter` (SMTP alerts on red status)
- **Background loops**: IMS refresh (2h), sensor poll (2min), data flow alert check (5min) β€” all push SSE events
### Core Python Modules
| Module | Purpose |
|---|---|
| `src/models/farquhar_model.py` | Leaf photosynthesis (FvCB mechanistic, Semillon sigmoid 28–32Β°C transition, vectorized `compute_all()`) |
| `src/data/ims_client.py` | IMS REST API client |
| `src/data/data_providers.py` | DataHub facade (6 services: Weather, VineSensor, PS, Energy, Advisory, Biology) |
| `src/data/thingsboard_client.py` | ThingsBoard REST client (22 devices, 4 trackers, plant asset) |
| `src/forecasting/predictor.py` | Multi-model ML regressor (LR/DT/RF/GBR/XGB) |
| `src/forecasting/ts_predictor.py` | Multi-horizon lag-based time-series |
| `src/forecasting/chronos_forecaster.py` | HuggingFace Chronos wrapper |
| `src/shading/tracker_optimizer.py` | Tilt-angle simulation & stress scheduling |
| `src/shading/solar_geometry.py` | Sun position, shadow projection, canopy PAR |
| `src/shading/tradeoff_engine.py` | InterventionGate (pipeline pattern) + minimum-dose offset search |
| `src/control_loop.py` | Real-time 15-min control orchestration (DI via `__init__()`) |
| `src/budget_audit.py` | Slot-level budget audit log (parquet) + weekly compliance report |
| `src/energy_budget.py` | Hierarchical Year→Month→Week→Day→Slot budget planner |
| `src/command_arbiter.py` | 5-level priority stack + hysteresis filter |
| `src/tracker_dispatcher.py` | Send tilt commands to TB trackers, verify execution |
| `src/advisor/day_ahead_advisor.py` | Gemini-powered daily planning engine |
| `src/day_ahead_planner.py` | DP trajectory optimizer for daily slot plans |
| `src/chatbot/vineyard_chatbot.py` | Gemini chatbot with tool dispatch + guardrails |
| `src/chatbot/guardrails.py` | Query classifier (EN+HE), response validator, confidence estimation, range validation, cross-source consistency |
| `backend/services/data_flow_monitor.py` | Per-source data freshness monitor (green/yellow/red) |
| `backend/services/email_alerter.py` | SMTP email alerts with per-source cooldown |
### Frontend
- **Pages**: Home, Agro, Trackers, Power, Monitoring (alarms + system health), Advisor, Control, Photosynthesis, Shading, Docs, Research
- **Custom hooks** (`src/hooks/`): `useWeather`, `useEnergy`, `useSensors`, `useChatbot`, `useControl`, `useAuth`, `useDataFlowStatus`, `useEventStream`
- **API client**: `src/lib/` β€” typed wrappers around backend endpoints
- **Auth**: JWT stored in `localStorage`; TanStack React Query for server state
### Data Flow
```
IMS API ──→ [Redis/CSV cache] ──→ Backend ──→ API Routes ──→ React Frontend
ThingsBoard sensors ────────────→ DataHub ──→ API Routes
Farquhar + ML models ───────────→ PhotosynthesisService ──→ /photosynthesis/*
TrackerOptimizer + EnergyBudget β†’ ControlSystem ──→ /control/*
DataFlowMonitor ────────────────→ /health/data-sources ──→ DataFlowStatus component
β†’ EmailAlerter ──→ SMTP alerts
Backend events ─────────────────→ SSE /events/stream ──→ auto-invalidate React Query
```
## Key Files to Know
- `config/settings.py` β€” central config (site coordinates, IMS channel IDs, panel geometry, budget params)
- `backend/api/main.py` β€” FastAPI app entry point (middleware, router registration)
- `backend/api/routes/` β€” all API endpoint implementations (~27 endpoints)
- `backend/workers/control_tick.py` β€” 15-min control loop cron entry point
- `backend/workers/daily_planner.py` β€” daily plan generation cron entry point
- `src/models/farquhar_model.py` β€” core mechanistic model
- `src/control_loop.py` β€” main control loop (sensors β†’ plan β†’ gate β†’ arbiter β†’ dispatch)
- `src/energy_budget.py` β€” hierarchical energy budget planner
- `src/chatbot/guardrails.py` β€” anti-hallucination guardrails (query classifier, range validation, cross-source checks)
- `backend/services/data_flow_monitor.py` β€” data source health monitoring
- `backend/services/email_alerter.py` β€” SMTP email alerts for data outages
- `backend/api/routes/events.py` β€” SSE event stream for live frontend updates
- `frontend/src/lib/api.ts` β€” API client with JWT auth
- `frontend/src/hooks/` β€” TanStack Query hooks for all API endpoints
- `scripts/load_test.py` β€” Locust load test (16 weighted endpoints)
- `context/3_todo.md` β€” current work items and backlog
- `ims_api_documentation.md` β€” IMS API reference (Hebrew + English)
## Deployment
| Platform | Target | Notes |
|---|---|---|
| HuggingFace Spaces | Backend | Docker, port 7860, see `backend/HF_README.md` |
| Cloudflare Pages | Frontend | `VITE_API_URL` env var points to HF backend |
| Streamlit Cloud | Legacy app | `IMS_API_TOKEN` secret, falls back to `sensors_wide_sample.csv` |
Large files (`Data/Seymour/sensors_wide.csv` ~982 MB, `outputs/`) are gitignored. Cloud deployments use `Data/Seymour/sensors_wide_sample.csv`.