Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enode API Changes #87

Open
wants to merge 23 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
23e4aa8
Create BaseModels for inverter data
neha-vard Apr 13, 2023
cd99e2e
Test
neha-vard Apr 13, 2023
db19834
Add fake inverter test
anyaparekh Apr 17, 2023
0eddcde
Create httpx auth class
jackypark9852 Apr 14, 2023
e1dadaf
Add enode link URL endpoint (#86)
AndrewLester Apr 23, 2023
3541f2f
[WIP] Add put endpoint for editing site (#88)
ericcccsliu Apr 23, 2023
f491656
Add post inverters for site endpoint
AndrewLester Apr 23, 2023
f4258e3
Add Enode auth test
AndrewLester Apr 24, 2023
ec1898c
Fix format
AndrewLester Apr 24, 2023
6715206
Change update inverters for site from post to put
AndrewLester Apr 25, 2023
d904f3a
Fix all review comments besides blocking client queries
AndrewLester Apr 27, 2023
ab5a5c1
remove redirectresponse class
ericcccsliu Apr 27, 2023
e4c0922
lint and format
ericcccsliu Apr 27, 2023
94c3767
Add client fetch to auth dependency and create new dependency for asy…
AndrewLester Apr 28, 2023
6329cb1
Use a pydantic model for client to serialize it in auth
AndrewLester Apr 29, 2023
af3ca34
Merge remote-tracking branch 'origin/main' into h4i/enode
AndrewLester May 4, 2023
4a04fd5
Add sentry init back and fix tests
AndrewLester May 4, 2023
381f849
Add logs for enode link and site inverters
AndrewLester May 4, 2023
5d622a2
Use httpx-auth to remove Enode auth code
AndrewLester May 4, 2023
e185d93
Fix format
AndrewLester May 4, 2023
246724d
Add test default values for Enode auth
AndrewLester May 16, 2023
7e80ee4
Handle case where no Enode user exists
AndrewLester May 18, 2023
819f55f
Fix import order
AndrewLester May 18, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
121 changes: 61 additions & 60 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 7 additions & 1 deletion pv_site_api/_db_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
import sqlalchemy as sa
import structlog
from pvsite_datamodel.read.generation import get_pv_generation_by_sites
from pvsite_datamodel.sqlmodels import ForecastSQL, ForecastValueSQL, SiteSQL
from pvsite_datamodel.sqlmodels import ForecastSQL, ForecastValueSQL, InverterSQL, SiteSQL
from sqlalchemy.orm import Session, aliased

from .pydantic_models import (
Expand Down Expand Up @@ -60,6 +60,12 @@ def _get_forecasts_for_horizon(
return list(session.execute(stmt))


def _get_inverters_by_site(session: Session, site_uuid: str) -> list[Row]:
query = session.query(InverterSQL).filter(InverterSQL.site_uuid == site_uuid)

return query.all()


def _get_latest_forecast_by_sites(
session: Session, site_uuids: list[str], start_utc: Optional[dt.datetime] = None
) -> list[Row]:
Expand Down
39 changes: 39 additions & 0 deletions pv_site_api/enode_auth.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
from typing import Optional

import httpx


class EnodeAuth(httpx.Auth):
def __init__(
self, client_id: str, client_secret: str, token_url: str, access_token: Optional[str] = None
):
self._client_id = client_id
self._client_secret = client_secret
self._token_url = token_url
self._access_token = access_token

def auth_flow(self, request: httpx.Request):
# Add the Authorization header to the request using the current access token
request.headers["Authorization"] = f"Bearer {self._access_token}"
response = yield request

if response.status_code == 401:
# The access token is no longer valid, refresh it
token_response = yield self._build_refresh_request()
self._update_access_token(token_response)
# Update the request's Authorization header with the new access token
request.headers["Authorization"] = f"Bearer {self._access_token}"
# Resend the request with the new access token
response = yield request
return response

def _build_refresh_request(self):
basic_auth = httpx.BasicAuth(self._client_id, self._client_secret)

data = {"grant_type": "client_credentials"}
request = next(basic_auth.auth_flow(httpx.Request("POST", self._token_url, data=data)))
return request

def _update_access_token(self, response):
response.read()
self._access_token = response.json()["access_token"]
39 changes: 39 additions & 0 deletions pv_site_api/fake.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@

from .pydantic_models import (
Forecast,
InverterInformation,
InverterLocation,
InverterProductionState,
Inverters,
InverterValues,
MultiplePVActual,
PVActualValue,
PVSiteAPIStatus,
Expand All @@ -19,6 +24,35 @@
fake_client_uuid = "c97f68cd-50e0-49bb-a850-108d4a9f7b7e"


def make_fake_inverters() -> Inverters:
"""Make fake inverters"""
inverter = InverterValues(
id="string",
vendor="EMA",
chargingLocationId="8d90101b-3f2f-462a-bbb4-1ed320d33bbe",
lastSeen="2020-04-07T17:04:26Z",
isReachable=True,
productionState=InverterProductionState(
productionRate=0,
isProducing=True,
totalLifetimeProduction=100152.56,
lastUpdated="2020-04-07T17:04:26Z",
),
information=InverterInformation(
id="string",
brand="EMA",
model="Sunny Boy",
siteName="Sunny Plant",
installationDate="2020-04-07T17:04:26Z",
),
location=InverterLocation(latitude=10.7197486, longitude=59.9173985),
)
inverters_list = Inverters(
inverters=[inverter],
)
return inverters_list


def make_fake_site() -> PVSites:
"""Make a fake site"""
pv_site = PVSiteMetadata(
Expand Down Expand Up @@ -86,3 +120,8 @@ def make_fake_status() -> PVSiteAPIStatus:
message="The API is up and running",
)
return pv_api_status


def make_fake_enode_link_url() -> str:
"""Make fake Enode link URL"""
return "https://enode.com"
Loading