File size: 9,480 Bytes
13fc29d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
# 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`.