diff --git a/.gitignore b/.gitignore index 338e667..825b83a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,3 @@ /src/.env .env -*.pyc +*.pyc \ No newline at end of file diff --git a/pv_site_api/main.py b/pv_site_api/main.py index 48111f9..198c694 100644 --- a/pv_site_api/main.py +++ b/pv_site_api/main.py @@ -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 @@ -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=( + f"Error processing generation values. " + f"One (or more) values are larger than {capacity_factor} " + f"times the site capacity of {site_capacity_kw} kWp. " + "Please adjust this generation value, the site capacity, " + "or contact quartz.support@openclimatefix.org." + ), + ) logger.debug(f"Adding {len(generation_values_df)} generation values") diff --git a/tests/test_generation.py b/tests/test_generation.py index a85f4e2..5a089e3 100644 --- a/tests/test_generation.py +++ b/tests/test_generation.py @@ -1,5 +1,4 @@ """ Test for main app """ - import json import uuid from datetime import datetime, timedelta, timezone @@ -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):