OpenEnv-compatible EV charging simulator focused on Indian residential grid conditions. The environment models charging and V2G behavior under time-varying tariffs, probabilistic grid outages, and battery degradation constraints.
This repository is designed for evaluator-friendly reproducibility:
- Deterministic grading endpoints per task
- FastAPI runtime with schema introspection
- Dockerized deployment path
- LLM-policy baseline runner via OpenAI-compatible API
- Python 3.10+
- Optional: Docker
- Optional: local LLM endpoint (Ollama) or hosted OpenAI-compatible endpoint
python -m venv .venv
# Windows PowerShell
.venv\Scripts\Activate.ps1
# macOS/Linux
source .venv/bin/activate
pip install -r requirements.txtuv syncThe project uses .env file for all LLM configuration. No code changes needed!
Create .env file:
cp .env.example .envEdit .env:
API_BASE_URL=https://api.openai.com/v1
MODEL_NAME=gpt-4o
API_KEY=your_openai_api_key_here
LLM_PROVIDER=openaiEdit .env:
API_BASE_URL=http://localhost:11434/v1
MODEL_NAME=llama3
API_KEY=ollama
LLM_PROVIDER=ollama
SERVER_URL=http://localhost:7860
PORT=7860Make sure Ollama is running:
ollama serveIn another terminal, pull the model:
ollama pull llama3python -m uvicorn server.app:app --host 0.0.0.0 --port 7860Server base URL: http://localhost:7860
python inference.pyThe inference script will:
- Read LLM configuration from
.envfile - Connect to the appropriate LLM provider (OpenAI or Ollama)
- Run all three tasks (night_owl, grid_survivor, v2g_profit)
- Output structured logs with
[START],[STEP],[END]markers
sh validate-submission.sh http://localhost:7860 .| Variable | Purpose | OpenAI Example | Ollama Example |
|---|---|---|---|
LLM_PROVIDER |
Which LLM to use | openai |
ollama |
API_BASE_URL |
LLM endpoint | https://api.openai.com/v1 |
http://localhost:11434/v1 |
MODEL_NAME |
Model identifier | gpt-4o |
llama3 |
API_KEY |
Authentication key | Your OpenAI key | ollama (dummy value) |
SERVER_URL |
Environment server | http://localhost:7860 |
http://localhost:7860 |
PORT |
API server port | 7860 |
7860 |
The simulator targets practical EV optimization in Indian grid conditions:
- Load shedding and voltage stress around evening peak windows
- Dynamic electricity pricing (off-peak vs peak slabs)
- Hardware diversity from home AC charging to DC fast charging
- Battery health impact from aggressive charging/discharging behavior
Contract is defined by openenv.yaml and mirrored in Pydantic models.
| Field | Type | Bounds | Meaning |
|---|---|---|---|
charge_rate_kw |
float | [-15.0, 50.0] |
Positive = charging, negative = V2G discharge |
| Field | Type | Meaning |
|---|---|---|
current_soc |
float | Battery state of charge in [0.0, 1.0] |
battery_health_soh |
float | Battery state of health in [0.0, 1.0] |
electricity_price_inr |
float | Current tariff in INR per unit |
is_grid_active |
bool | Grid availability flag |
time_of_day |
str | Simulation time formatted as HH:MM |
user_type |
str | Current archetype label |
target_soc |
float | Required SoC goal |
user_history |
list[float] | Last 5 synthetic departure-time observations |
GET /state returns extended state including:
current_hourtotal_bill_inrdeparture_time
Three built-in tasks are exposed by GET /tasks and scored via GET /grader/{task_id}.
| Task ID | Name | Difficulty | Max Steps | Grading Emphasis |
|---|---|---|---|---|
night_owl |
Night Charging | easy | 48 | SoC completion + cost efficiency |
grid_survivor |
Grid Constraint | medium | 48 | SoC + grid-aware behavior + cost |
v2g_profit |
V2G Profit Optimization | hard | 72 | SoC + net bill/profit + SoH preservation |
| Task ID | Threshold | Baseline |
|---|---|---|
night_owl |
0.70 |
0.742 |
grid_survivor |
0.70 |
0.911 |
v2g_profit |
0.70 |
0.767 |
Returns service status.
Example response:
{ "status": "healthy" }Returns environment metadata (name, description, version, category).
Returns JSON schema for action, observation, and state contracts.
Returns task descriptors (id, name, description, max_steps).
Resets episode state and returns initial observation.
Example request:
{}Example response:
{
"observation": {
"current_soc": 0.24,
"battery_health_soh": 1.0,
"electricity_price_inr": 6.5,
"is_grid_active": true,
"time_of_day": "22:00",
"user_type": "amazon_fleet",
"target_soc": 0.9,
"user_history": [6.03, 6.11, 5.94, 6.08, 5.99]
}
}Advances one 15-minute step.
Example request:
{ "charge_rate_kw": 12.5 }Example response:
{
"observation": {
"current_soc": 0.31,
"battery_health_soh": 0.9999,
"electricity_price_inr": 6.5,
"is_grid_active": true,
"time_of_day": "22:15",
"user_type": "amazon_fleet",
"target_soc": 0.9,
"user_history": [6.03, 6.11, 5.94, 6.08, 5.99]
},
"reward": 0.14,
"done": false,
"info": {
"info": "step successful"
}
}Returns full internal state object.
Returns deterministic final score for current episode state.
Example response:
{ "score": 0.811 }Connectivity placeholder for MCP-style checks.
- Step size:
0.25h(15 minutes) - Peak window:
18:00to22:00 - Peak tariff:
10.0 - Off-peak tariff:
6.5
is_grid_activesampled each step with higher outage chance during peak- Stability multiplier scales delivered power (
actual_kw = requested_kw * stability)
- Nominal capacity:
45.0 kWh - Hardware limits in environment constants include AC and DC rates
- SoH degradation scales with C-rate squared and applies stronger penalty for high-rate usage
inference.py provides a baseline LLM policy loop:
- Reset each task
- Call model with current observation
- Submit action to
/step - Grade at
/grader/{task_id} - Emit structured logs (
[START],[STEP],[END])
All LLM configuration is controlled by .env file — no code changes needed!
Use .env.example as a template:
cp .env.example .env
# Edit .env with your preferred LLM providerThen run inference:
python inference.pyThe script automatically reads all settings from .env:
LLM_PROVIDER(openai or ollama)API_BASE_URL(endpoint URL)MODEL_NAME(model identifier)API_KEY(authentication)SERVER_URL(environment API server)
Build and run:
docker build -t tata-nexon-grid-env .
docker run -p 7860:7860 tata-nexon-grid-envContainer startup command uses:
python -m uvicorn server.app:app --host 0.0.0.0 --port 7860python test_physics.pysh validate-submission.sh http://localhost:7860 .The validator checks:
POST /resetreturns HTTP200- Docker image builds successfully
/schemaexposes expected action constraints
ev-smart-grid-openenv/
├── data/
│ └── user_profiles.json
├── server/
│ ├── __init__.py
│ ├── app.py
│ ├── environment.py
│ ├── models.py
│ ├── tasks.py
│ └── utils.py
├── .env # ← Create this from .env.example
├── .env.example # ← Configuration template
├── Dockerfile
├── inference.py # ← Uses .env for LLM config
├── openenv.yaml
├── pyproject.toml
├── requirements.txt
├── test_physics.py
├── uv.lock
└── validate-submission.sh
- FastAPI
- Pydantic
- Uvicorn
- OpenAI Python SDK (OpenAI-compatible)
- python-dotenv (environment configuration)
- Requests/httpx
- OpenEnv Core
- Add richer evaluator diagnostics at episode end
- Expand user-profile driven initialization from external data
- Add scenario-specific benchmark policies (rule-based and RL)
- Extend metrics for grid stress and V2G profitability analysis