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

feat: validate generation values against site capacity #195

Merged
merged 8 commits into from
Oct 4, 2024
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
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
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
/src/.env
.env
*.pyc
*.pyc
1 change: 1 addition & 0 deletions .python-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
3.11.10
peterdudfield marked this conversation as resolved.
Show resolved Hide resolved
1 change: 0 additions & 1 deletion poetry.lock

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

20 changes: 20 additions & 0 deletions pv_site_api/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
from fastapi.responses import FileResponse, Response
from pvlib import irradiance, location, pvsystem
from pvsite_datamodel.pydantic_models import GenerationSum, PVSiteEditMetadata
from pvsite_datamodel.read.site import get_site_by_uuid
from pvsite_datamodel.read.status import get_latest_status
from pvsite_datamodel.read.user import get_user_by_email
from pvsite_datamodel.write.generation import insert_generation_values
Expand Down Expand Up @@ -276,7 +277,26 @@ def post_pv_actual(
}
)

# Set the error generation capacity factor from environment variable
capacity_factor = float(os.getenv("ERROR_GENERATION_CAPACITY_FACTOR", 1.1))

generation_values_df = pd.DataFrame(generations)
site = get_site_by_uuid(session=session, site_uuid=site_uuid)
site_capacity_kw = site.capacity_kw
exceeded_capacity = generation_values_df[
generation_values_df["power_kw"] > site_capacity_kw * capacity_factor
]
if len(exceeded_capacity) > 0:
raise HTTPException(
status_code=422,
detail=(
"Error processing generation values. "
peterdudfield marked this conversation as resolved.
Show resolved Hide resolved
"One (or more) values are larger than {capacity_factor} "
"times the site capacity of {site_capacity_kw} kWp. "
"Please adjust this generation value, the site capacity, "
"or contact [email protected]."
),
)
peterdudfield marked this conversation as resolved.
Show resolved Hide resolved

logger.debug(f"Adding {len(generation_values_df)} generation values")

Expand Down
42 changes: 34 additions & 8 deletions tests/test_generation.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
""" Test for main app """

import json
import uuid
from datetime import datetime, timedelta, timezone
Expand Down Expand Up @@ -146,25 +145,52 @@ def test_post_pv_actual(db_session, client, sites):
db_session.query(GenerationSQL).delete()

site_uuid = sites[0].site_uuid
site_capacity_kw = sites[0].capacity_kw

pv_actual_value = PVActualValue(
datetime_utc=datetime.now(timezone.utc), actual_generation_kw=73.3
# below capacity testcase
pv_actual_below_capacity = PVActualValue(
datetime_utc=datetime.now(timezone.utc), actual_generation_kw=site_capacity_kw - 1
)

# make iteration of pv values for one day at a specific site
pv_actual_iteration = MultiplePVActual(
site_uuid=str(site_uuid), pv_actual_values=[pv_actual_value]
pv_actual_iteration_below = MultiplePVActual(
site_uuid=str(site_uuid), pv_actual_values=[pv_actual_below_capacity]
)

# this makes sure the datetimes are iso strings
pv_actual_dict = json.loads(pv_actual_iteration.json())
pv_actual_dict_below = json.loads(pv_actual_iteration_below.json())

response = client.post(f"/sites/{site_uuid}/pv_actual", json=pv_actual_dict)
response = client.post(f"/sites/{site_uuid}/pv_actual", json=pv_actual_dict_below)
assert response.status_code == 200, response.text

generations = db_session.query(GenerationSQL).all()
assert len(generations) == 1
assert str(generations[0].site_uuid) == str(pv_actual_iteration.site_uuid)
assert str(generations[0].site_uuid) == str(pv_actual_iteration_below.site_uuid)


def test_post_pv_actual_above_capacity(db_session, client, sites):
db_session.query(GenerationSQL).delete()

site_uuid = sites[0].site_uuid
site_capacity_kw = sites[0].capacity_kw
capacity_factor = 1.1

# above capacity testcase
pv_actual_above_capacity = PVActualValue(
datetime_utc=datetime.now(timezone.utc),
actual_generation_kw=(site_capacity_kw * capacity_factor) + 1,
)

# make iteration of pv values for one day at a specific site
pv_actual_iteration_above = MultiplePVActual(
site_uuid=str(site_uuid), pv_actual_values=[pv_actual_above_capacity]
)

# this makes sure the datetimes are iso strings
pv_actual_dict_above = json.loads(pv_actual_iteration_above.json())
response_above = client.post(f"/sites/{site_uuid}/pv_actual", json=pv_actual_dict_above)

assert response_above.status_code == 422, response_above.text


def test_pv_actual_no_data(db_session, client, sites):
Expand Down
Loading