Skip to content

Commit 27a18f4

Browse files
authored
refactored dashboard_2 to use apis (#170)
* 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
1 parent fd69e12 commit 27a18f4

File tree

9 files changed

+421
-406
lines changed

9 files changed

+421
-406
lines changed

api/README.md

Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
# Solar Forecast API Documentation
2+
3+
## Overview
4+
5+
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:
6+
7+
1. `/forecast/`: Generate solar power forecasts.
8+
2. `/solar_inverters/enphase/auth_url`: Retrieve the Enphase authorization URL.
9+
3. `/solar_inverters/enphase/token_and_id`: Obtain an Enphase access token and system ID.
10+
11+
## Endpoints
12+
13+
### 1. Generate Solar Power Forecast
14+
15+
- **Endpoint:** `/forecast/`
16+
- **Method:** `POST`
17+
- **Description:** This endpoint generates a solar power forecast for a specified site and timestamp. It optionally includes real-time data from inverters if available.
18+
19+
#### Request Body:
20+
21+
- **ForecastRequest:**
22+
- `site` (PVSite, required): The site details for which the forecast is to be generated.
23+
- `timestamp` (string, optional): The timestamp for the forecast in ISO 8601 format. If not provided, the current time will be used.
24+
25+
- **PVSite:**
26+
- `latitude` (float, required): The latitude of the site. Must be between -90 and 90.
27+
- `longitude` (float, required): The longitude of the site. Must be between -180 and 180.
28+
- `capacity_kwp` (float, required): The capacity of the site in kilowatts peak (kWp). Must be a positive value.
29+
- `tilt` (float, optional, default=35): The tilt angle of the solar panels in degrees. Must be between 0 and 90.
30+
- `orientation` (float, optional, default=180): The orientation angle of the solar panels in degrees, measured from north. Must be between 0 and 360.
31+
- `inverter_type` (string, optional): The type of inverter used. Accepted values: `"enphase"`, `"solis"`, `"givenergy"`, `"solarman"`, or `None`.
32+
33+
#### Response:
34+
35+
- **200 OK**
36+
- **JSON Structure:**
37+
```json
38+
{
39+
"timestamp": "2023-08-14 10:00:00",
40+
"predictions": {
41+
"power_kw": [values],
42+
"power_kw_no_live_pv": [values]
43+
}
44+
}
45+
```
46+
- `timestamp` (string): The formatted timestamp of the forecast.
47+
- `predictions` (dictionary): The forecasted power data. If inverter data is available, it will also include `power_kw_no_live_pv` without inverter data.
48+
49+
### 2. Retrieve Enphase Authorization URL
50+
51+
- **Endpoint:** `/solar_inverters/enphase/auth_url`
52+
- **Method:** `GET`
53+
- **Description:** This endpoint returns the authorization URL required to initiate the OAuth flow for Enphase inverters.
54+
55+
#### Response:
56+
57+
- **200 OK**
58+
- **JSON Structure:**
59+
```json
60+
{
61+
"auth_url": "https://api.enphaseenergy.com/oauth/authorize?client_id=..."
62+
}
63+
```
64+
- `auth_url` (string): The URL to redirect the user to for Enphase authorization.
65+
66+
### 3. Obtain Enphase Access Token and System ID
67+
68+
- **Endpoint:** `/solar_inverters/enphase/token_and_id`
69+
- **Method:** `POST`
70+
- **Description:** This endpoint exchanges an authorization code for an access token and retrieves the system ID of the Enphase solar inverter.
71+
72+
#### Request Body:
73+
74+
- **TokenRequest:**
75+
- `redirect_url` (string, required): The URL to which the user was redirected after Enphase authorization, containing the authorization code.
76+
77+
#### Response:
78+
79+
- **200 OK**
80+
- **JSON Structure:**
81+
```json
82+
{
83+
"access_token": "abc123...",
84+
"enphase_system_id": "123456789"
85+
}
86+
```
87+
- `access_token` (string): The access token for Enphase API.
88+
- `enphase_system_id` (string): The system ID of the Enphase solar inverter.
89+
90+
- **400 Bad Request**
91+
- **Error Message:**
92+
```json
93+
{
94+
"detail": "Invalid redirect URL"
95+
}
96+
```
97+
- **Description:** The request was not properly formatted or did not contain the necessary authorization code.
98+
99+
## Error Handling
100+
101+
All endpoints will return appropriate HTTP status codes. Common responses include:
102+
103+
- **200 OK:** The request was successful.
104+
- **400 Bad Request:** The request was malformed or contained invalid data.
105+
- **500 Internal Server Error:** An unexpected error occurred on the server.
106+
107+
## Example Usage
108+
109+
### Generate Solar Power Forecast
110+
111+
**Request:**
112+
113+
```bash
114+
curl -X POST "http://localhost:8000/forecast/" -H "Content-Type: application/json" -d '{
115+
"site": {
116+
"latitude": 37.7749,
117+
"longitude": -122.4194,
118+
"capacity_kwp": 5.0,
119+
"tilt": 30,
120+
"orientation": 180,
121+
"inverter_type": "enphase"
122+
},
123+
"timestamp": "2023-08-14T10:00:00Z"
124+
}'
125+
```
126+
127+
**Response:**
128+
129+
```json
130+
{
131+
"timestamp": "2023-08-14 10:00:00",
132+
"predictions": {
133+
"power_kw": [values],
134+
"power_kw_no_live_pv": [values]
135+
}
136+
}
137+
```
138+
139+
### Retrieve Enphase Authorization URL
140+
141+
**Request:**
142+
143+
```bash
144+
curl -X GET "http://localhost:8000/solar_inverters/enphase/auth_url"
145+
```
146+
147+
**Response:**
148+
149+
```json
150+
{
151+
"auth_url": "https://api.enphaseenergy.com/oauth/authorize?client_id=..."
152+
}
153+
```
154+
155+
### Obtain Enphase Access Token and System ID
156+
157+
**Request:**
158+
159+
```bash
160+
curl -X POST "http://localhost:8000/solar_inverters/enphase/token_and_id" -H "Content-Type: application/json" -d '{
161+
"redirect_url": "https://yourapp.com/callback?code=abc123"
162+
}'
163+
```
164+
165+
**Response:**
166+
167+
```json
168+
{
169+
"access_token": "abc123...",
170+
"enphase_system_id": "123456789"
171+
}
172+
```

api/app/api.py

Lines changed: 54 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,25 @@
1-
from fastapi import FastAPI
1+
import os
2+
from datetime import datetime, timezone
3+
from fastapi import FastAPI, HTTPException
24
from fastapi.middleware.cors import CORSMiddleware
3-
from quartz_solar_forecast.pydantic_models import PVSite
5+
import pandas as pd
6+
from dotenv import load_dotenv
47
from quartz_solar_forecast.forecast import run_forecast
8+
from quartz_solar_forecast.pydantic_models import PVSite, ForecastRequest, TokenRequest
9+
from quartz_solar_forecast.inverters.enphase import get_enphase_auth_url, get_enphase_access_token
10+
11+
load_dotenv()
512

613
app = FastAPI()
714

15+
# CORS middleware setup
816
origins = [
917
"http://localhost:5173",
10-
"localhost:5173"
18+
"localhost:5173",
19+
"http://localhost:8501",
20+
"localhost:8501"
1121
]
1222

13-
1423
app.add_middleware(
1524
CORSMiddleware,
1625
allow_origins=origins,
@@ -20,6 +29,44 @@
2029
)
2130

2231
@app.post("/forecast/")
23-
async def forecast(site:PVSite):
24-
df =run_forecast(site)
25-
return df.to_dict()
32+
def forecast(forecast_request: ForecastRequest):
33+
site = forecast_request.site
34+
ts = forecast_request.timestamp if forecast_request.timestamp else datetime.now(timezone.utc).isoformat()
35+
36+
timestamp = pd.Timestamp(ts).tz_localize(None)
37+
formatted_timestamp = timestamp.strftime('%Y-%m-%d %H:%M:%S')
38+
39+
site_no_live = PVSite(latitude=site.latitude, longitude=site.longitude, capacity_kwp=site.capacity_kwp)
40+
predictions_no_live = run_forecast(site=site_no_live, ts=timestamp)
41+
42+
if not site.inverter_type:
43+
predictions = predictions_no_live
44+
else:
45+
predictions_with_live = run_forecast(site=site, ts=timestamp)
46+
predictions_with_live['power_kw_no_live_pv'] = predictions_no_live['power_kw']
47+
predictions = predictions_with_live
48+
49+
response = {
50+
"timestamp": formatted_timestamp,
51+
"predictions": predictions.to_dict(),
52+
}
53+
54+
return response
55+
56+
@app.get("/solar_inverters/enphase/auth_url")
57+
def get_enphase_authorization_url():
58+
auth_url = get_enphase_auth_url()
59+
return {"auth_url": auth_url}
60+
61+
@app.post("/solar_inverters/enphase/token_and_id")
62+
def get_enphase_token_and_system_id(request: TokenRequest):
63+
if "?code=" not in request.redirect_url:
64+
raise HTTPException(status_code=400, detail="Invalid redirect URL")
65+
66+
auth_code = request.redirect_url.split("?code=")[1]
67+
try:
68+
access_token = get_enphase_access_token(auth_code)
69+
enphase_system_id = os.getenv("ENPHASE_SYSTEM_ID")
70+
return {"access_token": access_token, "enphase_system_id": enphase_system_id}
71+
except Exception as e:
72+
raise HTTPException(status_code=400, detail=f"Error getting access token and system ID: {str(e)}")

api/main.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import uvicorn
22

3-
43
if __name__ == "__main__":
5-
uvicorn.run("app.api:app", host="0.0.0.0", port=8000, reload=True)
4+
uvicorn.run("app.api:app", host="localhost", port=8000, reload=True)

dashboards/dashboard_2/README.md

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -9,34 +9,39 @@ https://github.com/user-attachments/assets/940ca4a7-65a4-40ea-a602-ea0f65e96746
99
## Features
1010

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

19-
## How to Run
19+
## Development Environment Setup
2020

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

24-
2. Set up environment variables (if applicable):
24+
2. Set up environment variables for your inverter (if applicable):
2525

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

35-
3. Navigate to the `dashboards/dashboard_2` directory.
30+
## How to Run the Backend
3631

37-
4. Run the Streamlit app: `streamlit run app.py`
32+
1. Navigate to the `api` directory
3833

39-
5. Open your web browser and go to the URL provided by Streamlit (usually `http://localhost:8501`).
34+
2. Run the API: `python main.py`
35+
36+
3. Ensure that this API is running before you use the frontend
37+
38+
## How to Run the Frontend
39+
40+
1. Navigate to the `dashboards/dashboard_2` directory.
41+
42+
2. Run the Streamlit app: `streamlit run app.py`
43+
44+
3. Open your web browser and go to the URL provided by Streamlit (usually `http://localhost:8501`).
4045

4146
## Using the App
4247

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

4853
2. **Select Inverter Type:**
4954

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

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

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

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

0 commit comments

Comments
 (0)