Skip to content

Commit

Permalink
refactored dashboard_2 to use apis (#170)
Browse files Browse the repository at this point in the history
* refactor

* all apis in dashboard_2

* refactored api to use enphase imports

* refactored make_pv_data

* rm unnecessary imports

* no inv vs inv

* enphase state

* models

* removed logging and try catch

* path fix

* prev code

* less changes

* Update forecast.py

* Update forecast.py

* Update forecast.py

* ui

* Update requirements.txt

* models to schemas

* endpt change

* solarman changes

* load env

* rm all spcl mentions of enphase

* en

* change

* not working

* made it work!

* rm unnecessary vars

* unused imports rm

* reused api func

* rm schemas and incl in pydantic

* rm unused

* coupled api res

* ui

* unused

* readme update

* rm unused

* enphase token in sesh state

* rm dups

* rm space

* docs

* no inv

* renamed req to forecast_req

* rm unnec

* backend works, frontend needs to be fixed

* made it work gg

* rm unnecessary

* rm unn

* upd read

* cli context
  • Loading branch information
aryanbhosale authored Aug 15, 2024
1 parent fd69e12 commit 27a18f4
Show file tree
Hide file tree
Showing 9 changed files with 421 additions and 406 deletions.
172 changes: 172 additions & 0 deletions api/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
# Solar Forecast API Documentation

## Overview

This API provides solar power forecast data based on the given site information and handles authorization with Enphase solar inverters. It has been developed using FastAPI and includes the following key endpoints:

1. `/forecast/`: Generate solar power forecasts.
2. `/solar_inverters/enphase/auth_url`: Retrieve the Enphase authorization URL.
3. `/solar_inverters/enphase/token_and_id`: Obtain an Enphase access token and system ID.

## Endpoints

### 1. Generate Solar Power Forecast

- **Endpoint:** `/forecast/`
- **Method:** `POST`
- **Description:** This endpoint generates a solar power forecast for a specified site and timestamp. It optionally includes real-time data from inverters if available.

#### Request Body:

- **ForecastRequest:**
- `site` (PVSite, required): The site details for which the forecast is to be generated.
- `timestamp` (string, optional): The timestamp for the forecast in ISO 8601 format. If not provided, the current time will be used.

- **PVSite:**
- `latitude` (float, required): The latitude of the site. Must be between -90 and 90.
- `longitude` (float, required): The longitude of the site. Must be between -180 and 180.
- `capacity_kwp` (float, required): The capacity of the site in kilowatts peak (kWp). Must be a positive value.
- `tilt` (float, optional, default=35): The tilt angle of the solar panels in degrees. Must be between 0 and 90.
- `orientation` (float, optional, default=180): The orientation angle of the solar panels in degrees, measured from north. Must be between 0 and 360.
- `inverter_type` (string, optional): The type of inverter used. Accepted values: `"enphase"`, `"solis"`, `"givenergy"`, `"solarman"`, or `None`.

#### Response:

- **200 OK**
- **JSON Structure:**
```json
{
"timestamp": "2023-08-14 10:00:00",
"predictions": {
"power_kw": [values],
"power_kw_no_live_pv": [values]
}
}
```
- `timestamp` (string): The formatted timestamp of the forecast.
- `predictions` (dictionary): The forecasted power data. If inverter data is available, it will also include `power_kw_no_live_pv` without inverter data.

### 2. Retrieve Enphase Authorization URL

- **Endpoint:** `/solar_inverters/enphase/auth_url`
- **Method:** `GET`
- **Description:** This endpoint returns the authorization URL required to initiate the OAuth flow for Enphase inverters.

#### Response:

- **200 OK**
- **JSON Structure:**
```json
{
"auth_url": "https://api.enphaseenergy.com/oauth/authorize?client_id=..."
}
```
- `auth_url` (string): The URL to redirect the user to for Enphase authorization.

### 3. Obtain Enphase Access Token and System ID

- **Endpoint:** `/solar_inverters/enphase/token_and_id`
- **Method:** `POST`
- **Description:** This endpoint exchanges an authorization code for an access token and retrieves the system ID of the Enphase solar inverter.

#### Request Body:

- **TokenRequest:**
- `redirect_url` (string, required): The URL to which the user was redirected after Enphase authorization, containing the authorization code.

#### Response:

- **200 OK**
- **JSON Structure:**
```json
{
"access_token": "abc123...",
"enphase_system_id": "123456789"
}
```
- `access_token` (string): The access token for Enphase API.
- `enphase_system_id` (string): The system ID of the Enphase solar inverter.

- **400 Bad Request**
- **Error Message:**
```json
{
"detail": "Invalid redirect URL"
}
```
- **Description:** The request was not properly formatted or did not contain the necessary authorization code.

## Error Handling

All endpoints will return appropriate HTTP status codes. Common responses include:

- **200 OK:** The request was successful.
- **400 Bad Request:** The request was malformed or contained invalid data.
- **500 Internal Server Error:** An unexpected error occurred on the server.

## Example Usage

### Generate Solar Power Forecast

**Request:**

```bash
curl -X POST "http://localhost:8000/forecast/" -H "Content-Type: application/json" -d '{
"site": {
"latitude": 37.7749,
"longitude": -122.4194,
"capacity_kwp": 5.0,
"tilt": 30,
"orientation": 180,
"inverter_type": "enphase"
},
"timestamp": "2023-08-14T10:00:00Z"
}'
```

**Response:**

```json
{
"timestamp": "2023-08-14 10:00:00",
"predictions": {
"power_kw": [values],
"power_kw_no_live_pv": [values]
}
}
```

### Retrieve Enphase Authorization URL

**Request:**

```bash
curl -X GET "http://localhost:8000/solar_inverters/enphase/auth_url"
```

**Response:**

```json
{
"auth_url": "https://api.enphaseenergy.com/oauth/authorize?client_id=..."
}
```

### Obtain Enphase Access Token and System ID

**Request:**

```bash
curl -X POST "http://localhost:8000/solar_inverters/enphase/token_and_id" -H "Content-Type: application/json" -d '{
"redirect_url": "https://yourapp.com/callback?code=abc123"
}'
```

**Response:**

```json
{
"access_token": "abc123...",
"enphase_system_id": "123456789"
}
```
61 changes: 54 additions & 7 deletions api/app/api.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,25 @@
from fastapi import FastAPI
import os
from datetime import datetime, timezone
from fastapi import FastAPI, HTTPException
from fastapi.middleware.cors import CORSMiddleware
from quartz_solar_forecast.pydantic_models import PVSite
import pandas as pd
from dotenv import load_dotenv
from quartz_solar_forecast.forecast import run_forecast
from quartz_solar_forecast.pydantic_models import PVSite, ForecastRequest, TokenRequest
from quartz_solar_forecast.inverters.enphase import get_enphase_auth_url, get_enphase_access_token

load_dotenv()

app = FastAPI()

# CORS middleware setup
origins = [
"http://localhost:5173",
"localhost:5173"
"localhost:5173",
"http://localhost:8501",
"localhost:8501"
]


app.add_middleware(
CORSMiddleware,
allow_origins=origins,
Expand All @@ -20,6 +29,44 @@
)

@app.post("/forecast/")
async def forecast(site:PVSite):
df =run_forecast(site)
return df.to_dict()
def forecast(forecast_request: ForecastRequest):
site = forecast_request.site
ts = forecast_request.timestamp if forecast_request.timestamp else datetime.now(timezone.utc).isoformat()

timestamp = pd.Timestamp(ts).tz_localize(None)
formatted_timestamp = timestamp.strftime('%Y-%m-%d %H:%M:%S')

site_no_live = PVSite(latitude=site.latitude, longitude=site.longitude, capacity_kwp=site.capacity_kwp)
predictions_no_live = run_forecast(site=site_no_live, ts=timestamp)

if not site.inverter_type:
predictions = predictions_no_live
else:
predictions_with_live = run_forecast(site=site, ts=timestamp)
predictions_with_live['power_kw_no_live_pv'] = predictions_no_live['power_kw']
predictions = predictions_with_live

response = {
"timestamp": formatted_timestamp,
"predictions": predictions.to_dict(),
}

return response

@app.get("/solar_inverters/enphase/auth_url")
def get_enphase_authorization_url():
auth_url = get_enphase_auth_url()
return {"auth_url": auth_url}

@app.post("/solar_inverters/enphase/token_and_id")
def get_enphase_token_and_system_id(request: TokenRequest):
if "?code=" not in request.redirect_url:
raise HTTPException(status_code=400, detail="Invalid redirect URL")

auth_code = request.redirect_url.split("?code=")[1]
try:
access_token = get_enphase_access_token(auth_code)
enphase_system_id = os.getenv("ENPHASE_SYSTEM_ID")
return {"access_token": access_token, "enphase_system_id": enphase_system_id}
except Exception as e:
raise HTTPException(status_code=400, detail=f"Error getting access token and system ID: {str(e)}")
3 changes: 1 addition & 2 deletions api/main.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import uvicorn


if __name__ == "__main__":
uvicorn.run("app.api:app", host="0.0.0.0", port=8000, reload=True)
uvicorn.run("app.api:app", host="localhost", port=8000, reload=True)
35 changes: 20 additions & 15 deletions dashboards/dashboard_2/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,34 +9,39 @@ https://github.com/user-attachments/assets/940ca4a7-65a4-40ea-a602-ea0f65e96746
## Features

- Configure PV site parameters (latitude, longitude, capacity)
- Select inverter type (No Inverter or Enphase)
- Select inverter type (No Inverter, Enphase, Solis, GivEnergy, or Solarman)
- Enphase API authentication flow (if applicable)
- Run solar forecast
- Visualize forecast results with interactive charts
- Compare forecasts with and without recent PV data (if applicable)
- Display raw forecast data and provide an option to download it as CSV

## How to Run
## Development Environment Setup

1. Clone the repository and install all the dependencies in a virtual environment on a Linux System(or WSL):
`pip install -e .` and `pip install -r requirements.txt`

2. Set up environment variables (if applicable):
2. Set up environment variables for your inverter (if applicable):

- Create a `.env` file in your root directory
- Add the following variables:
```
ENPHASE_CLIENT_ID=your_client_id
ENPHASE_CLIENT_SECRET=your_client_secret
ENPHASE_API_KEY=your_api_key
ENPHASE_SYSTEM_ID=your_system_id
```
- Check out `.env.example` file and copy paste the contents of the file in the `.env` file that you just created
- Replace the placeholder for all the variables that are relevant to your inverter

3. Navigate to the `dashboards/dashboard_2` directory.
## How to Run the Backend

4. Run the Streamlit app: `streamlit run app.py`
1. Navigate to the `api` directory

5. Open your web browser and go to the URL provided by Streamlit (usually `http://localhost:8501`).
2. Run the API: `python main.py`

3. Ensure that this API is running before you use the frontend

## How to Run the Frontend

1. Navigate to the `dashboards/dashboard_2` directory.

2. Run the Streamlit app: `streamlit run app.py`

3. Open your web browser and go to the URL provided by Streamlit (usually `http://localhost:8501`).

## Using the App

Expand All @@ -47,7 +52,7 @@ https://github.com/user-attachments/assets/940ca4a7-65a4-40ea-a602-ea0f65e96746

2. **Select Inverter Type:**

- Choose between "No Inverter" and "Enphase" from the dropdown menu.
- Choose between "No Inverter", "Enphase", "Solis", "GivEnergy", and "Solarman" from the dropdown menu.

3. **Enphase Authorization (if applicable):**

Expand All @@ -69,4 +74,4 @@ https://github.com/user-attachments/assets/940ca4a7-65a4-40ea-a602-ea0f65e96746
## Additional Information

- Forecasts are generated for the next 48 hours in 15-minute intervals.
- The app demonstrates the impact of using recent PV data (from Enphase) on forecast accuracy.
- The app demonstrates the impact of using recent PV data (from Enphase) on forecast accuracy.
Loading

0 comments on commit 27a18f4

Please sign in to comment.