From af5e4a753adb652bcb187008cb68ce3d9d325961 Mon Sep 17 00:00:00 2001 From: Dominique Lasserre Date: Sun, 19 Jan 2025 18:12:50 +0100 Subject: [PATCH] PVForecast: planes as nested config (list) --- .gitignore | 3 + docs/_generated/config.md | 509 +-- docs/akkudoktoreos/prediction.md | 8 +- openapi.json | 3489 ++--------------- scripts/generate_config_md.py | 54 +- single_test_prediction.py | 53 +- src/akkudoktoreos/prediction/pvforecast.py | 649 +-- .../prediction/pvforecastakkudoktor.py | 94 +- .../prediction/pvforecastimport.py | 18 +- src/akkudoktoreos/utils/docs.py | 42 + tests/test_pvforecast.py | 243 +- tests/test_pvforecastakkudoktor.py | 51 +- tests/test_pvforecastimport.py | 14 +- 13 files changed, 1085 insertions(+), 4142 deletions(-) create mode 100644 src/akkudoktoreos/utils/docs.py diff --git a/.gitignore b/.gitignore index 0d62700..91ef5d7 100644 --- a/.gitignore +++ b/.gitignore @@ -260,3 +260,6 @@ tests/testdata/new_optimize_result* tests/testdata/openapi-new.json tests/testdata/openapi-new.md tests/testdata/config-new.md + +# FastHTML session key +.sesskey diff --git a/docs/_generated/config.md b/docs/_generated/config.md index c7d2109..b9ec9d5 100644 --- a/docs/_generated/config.md +++ b/docs/_generated/config.md @@ -510,109 +510,13 @@ Validators: | Name | Environment Variable | Type | Read-Only | Default | Description | | ---- | -------------------- | ---- | --------- | ------- | ----------- | | provider | `EOS_PVFORECAST__PROVIDER` | `Optional[str]` | `rw` | `None` | PVForecast provider id of provider to be used. | -| pvforecast0_surface_tilt | `EOS_PVFORECAST__PVFORECAST0_SURFACE_TILT` | `Optional[float]` | `rw` | `None` | Tilt angle from horizontal plane. Ignored for two-axis tracking. | -| pvforecast0_surface_azimuth | `EOS_PVFORECAST__PVFORECAST0_SURFACE_AZIMUTH` | `Optional[float]` | `rw` | `None` | Orientation (azimuth angle) of the (fixed) plane. Clockwise from north (north=0, east=90, south=180, west=270). | -| pvforecast0_userhorizon | `EOS_PVFORECAST__PVFORECAST0_USERHORIZON` | `Optional[List[float]]` | `rw` | `None` | Elevation of horizon in degrees, at equally spaced azimuth clockwise from north. | -| pvforecast0_peakpower | `EOS_PVFORECAST__PVFORECAST0_PEAKPOWER` | `Optional[float]` | `rw` | `None` | Nominal power of PV system in kW. | -| pvforecast0_pvtechchoice | `EOS_PVFORECAST__PVFORECAST0_PVTECHCHOICE` | `Optional[str]` | `rw` | `crystSi` | PV technology. One of 'crystSi', 'CIS', 'CdTe', 'Unknown'. | -| pvforecast0_mountingplace | `EOS_PVFORECAST__PVFORECAST0_MOUNTINGPLACE` | `Optional[str]` | `rw` | `free` | Type of mounting for PV system. Options are 'free' for free-standing and 'building' for building-integrated. | -| pvforecast0_loss | `EOS_PVFORECAST__PVFORECAST0_LOSS` | `Optional[float]` | `rw` | `14.0` | Sum of PV system losses in percent | -| pvforecast0_trackingtype | `EOS_PVFORECAST__PVFORECAST0_TRACKINGTYPE` | `Optional[int]` | `rw` | `None` | Type of suntracking. 0=fixed, 1=single horizontal axis aligned north-south, 2=two-axis tracking, 3=vertical axis tracking, 4=single horizontal axis aligned east-west, 5=single inclined axis aligned north-south. | -| pvforecast0_optimal_surface_tilt | `EOS_PVFORECAST__PVFORECAST0_OPTIMAL_SURFACE_TILT` | `Optional[bool]` | `rw` | `False` | Calculate the optimum tilt angle. Ignored for two-axis tracking. | -| pvforecast0_optimalangles | `EOS_PVFORECAST__PVFORECAST0_OPTIMALANGLES` | `Optional[bool]` | `rw` | `False` | Calculate the optimum tilt and azimuth angles. Ignored for two-axis tracking. | -| pvforecast0_albedo | `EOS_PVFORECAST__PVFORECAST0_ALBEDO` | `Optional[float]` | `rw` | `None` | Proportion of the light hitting the ground that it reflects back. | -| pvforecast0_module_model | `EOS_PVFORECAST__PVFORECAST0_MODULE_MODEL` | `Optional[str]` | `rw` | `None` | Model of the PV modules of this plane. | -| pvforecast0_inverter_model | `EOS_PVFORECAST__PVFORECAST0_INVERTER_MODEL` | `Optional[str]` | `rw` | `None` | Model of the inverter of this plane. | -| pvforecast0_inverter_paco | `EOS_PVFORECAST__PVFORECAST0_INVERTER_PACO` | `Optional[int]` | `rw` | `None` | AC power rating of the inverter. [W] | -| pvforecast0_modules_per_string | `EOS_PVFORECAST__PVFORECAST0_MODULES_PER_STRING` | `Optional[int]` | `rw` | `None` | Number of the PV modules of the strings of this plane. | -| pvforecast0_strings_per_inverter | `EOS_PVFORECAST__PVFORECAST0_STRINGS_PER_INVERTER` | `Optional[int]` | `rw` | `None` | Number of the strings of the inverter of this plane. | -| pvforecast1_surface_tilt | `EOS_PVFORECAST__PVFORECAST1_SURFACE_TILT` | `Optional[float]` | `rw` | `None` | Tilt angle from horizontal plane. Ignored for two-axis tracking. | -| pvforecast1_surface_azimuth | `EOS_PVFORECAST__PVFORECAST1_SURFACE_AZIMUTH` | `Optional[float]` | `rw` | `None` | Orientation (azimuth angle) of the (fixed) plane. Clockwise from north (north=0, east=90, south=180, west=270). | -| pvforecast1_userhorizon | `EOS_PVFORECAST__PVFORECAST1_USERHORIZON` | `Optional[List[float]]` | `rw` | `None` | Elevation of horizon in degrees, at equally spaced azimuth clockwise from north. | -| pvforecast1_peakpower | `EOS_PVFORECAST__PVFORECAST1_PEAKPOWER` | `Optional[float]` | `rw` | `None` | Nominal power of PV system in kW. | -| pvforecast1_pvtechchoice | `EOS_PVFORECAST__PVFORECAST1_PVTECHCHOICE` | `Optional[str]` | `rw` | `crystSi` | PV technology. One of 'crystSi', 'CIS', 'CdTe', 'Unknown'. | -| pvforecast1_mountingplace | `EOS_PVFORECAST__PVFORECAST1_MOUNTINGPLACE` | `Optional[str]` | `rw` | `free` | Type of mounting for PV system. Options are 'free' for free-standing and 'building' for building-integrated. | -| pvforecast1_loss | `EOS_PVFORECAST__PVFORECAST1_LOSS` | `Optional[float]` | `rw` | `14.0` | Sum of PV system losses in percent | -| pvforecast1_trackingtype | `EOS_PVFORECAST__PVFORECAST1_TRACKINGTYPE` | `Optional[int]` | `rw` | `None` | Type of suntracking. 0=fixed, 1=single horizontal axis aligned north-south, 2=two-axis tracking, 3=vertical axis tracking, 4=single horizontal axis aligned east-west, 5=single inclined axis aligned north-south. | -| pvforecast1_optimal_surface_tilt | `EOS_PVFORECAST__PVFORECAST1_OPTIMAL_SURFACE_TILT` | `Optional[bool]` | `rw` | `False` | Calculate the optimum tilt angle. Ignored for two-axis tracking. | -| pvforecast1_optimalangles | `EOS_PVFORECAST__PVFORECAST1_OPTIMALANGLES` | `Optional[bool]` | `rw` | `False` | Calculate the optimum tilt and azimuth angles. Ignored for two-axis tracking. | -| pvforecast1_albedo | `EOS_PVFORECAST__PVFORECAST1_ALBEDO` | `Optional[float]` | `rw` | `None` | Proportion of the light hitting the ground that it reflects back. | -| pvforecast1_module_model | `EOS_PVFORECAST__PVFORECAST1_MODULE_MODEL` | `Optional[str]` | `rw` | `None` | Model of the PV modules of this plane. | -| pvforecast1_inverter_model | `EOS_PVFORECAST__PVFORECAST1_INVERTER_MODEL` | `Optional[str]` | `rw` | `None` | Model of the inverter of this plane. | -| pvforecast1_inverter_paco | `EOS_PVFORECAST__PVFORECAST1_INVERTER_PACO` | `Optional[int]` | `rw` | `None` | AC power rating of the inverter. [W] | -| pvforecast1_modules_per_string | `EOS_PVFORECAST__PVFORECAST1_MODULES_PER_STRING` | `Optional[int]` | `rw` | `None` | Number of the PV modules of the strings of this plane. | -| pvforecast1_strings_per_inverter | `EOS_PVFORECAST__PVFORECAST1_STRINGS_PER_INVERTER` | `Optional[int]` | `rw` | `None` | Number of the strings of the inverter of this plane. | -| pvforecast2_surface_tilt | `EOS_PVFORECAST__PVFORECAST2_SURFACE_TILT` | `Optional[float]` | `rw` | `None` | Tilt angle from horizontal plane. Ignored for two-axis tracking. | -| pvforecast2_surface_azimuth | `EOS_PVFORECAST__PVFORECAST2_SURFACE_AZIMUTH` | `Optional[float]` | `rw` | `None` | Orientation (azimuth angle) of the (fixed) plane. Clockwise from north (north=0, east=90, south=180, west=270). | -| pvforecast2_userhorizon | `EOS_PVFORECAST__PVFORECAST2_USERHORIZON` | `Optional[List[float]]` | `rw` | `None` | Elevation of horizon in degrees, at equally spaced azimuth clockwise from north. | -| pvforecast2_peakpower | `EOS_PVFORECAST__PVFORECAST2_PEAKPOWER` | `Optional[float]` | `rw` | `None` | Nominal power of PV system in kW. | -| pvforecast2_pvtechchoice | `EOS_PVFORECAST__PVFORECAST2_PVTECHCHOICE` | `Optional[str]` | `rw` | `crystSi` | PV technology. One of 'crystSi', 'CIS', 'CdTe', 'Unknown'. | -| pvforecast2_mountingplace | `EOS_PVFORECAST__PVFORECAST2_MOUNTINGPLACE` | `Optional[str]` | `rw` | `free` | Type of mounting for PV system. Options are 'free' for free-standing and 'building' for building-integrated. | -| pvforecast2_loss | `EOS_PVFORECAST__PVFORECAST2_LOSS` | `Optional[float]` | `rw` | `14.0` | Sum of PV system losses in percent | -| pvforecast2_trackingtype | `EOS_PVFORECAST__PVFORECAST2_TRACKINGTYPE` | `Optional[int]` | `rw` | `None` | Type of suntracking. 0=fixed, 1=single horizontal axis aligned north-south, 2=two-axis tracking, 3=vertical axis tracking, 4=single horizontal axis aligned east-west, 5=single inclined axis aligned north-south. | -| pvforecast2_optimal_surface_tilt | `EOS_PVFORECAST__PVFORECAST2_OPTIMAL_SURFACE_TILT` | `Optional[bool]` | `rw` | `False` | Calculate the optimum tilt angle. Ignored for two-axis tracking. | -| pvforecast2_optimalangles | `EOS_PVFORECAST__PVFORECAST2_OPTIMALANGLES` | `Optional[bool]` | `rw` | `False` | Calculate the optimum tilt and azimuth angles. Ignored for two-axis tracking. | -| pvforecast2_albedo | `EOS_PVFORECAST__PVFORECAST2_ALBEDO` | `Optional[float]` | `rw` | `None` | Proportion of the light hitting the ground that it reflects back. | -| pvforecast2_module_model | `EOS_PVFORECAST__PVFORECAST2_MODULE_MODEL` | `Optional[str]` | `rw` | `None` | Model of the PV modules of this plane. | -| pvforecast2_inverter_model | `EOS_PVFORECAST__PVFORECAST2_INVERTER_MODEL` | `Optional[str]` | `rw` | `None` | Model of the inverter of this plane. | -| pvforecast2_inverter_paco | `EOS_PVFORECAST__PVFORECAST2_INVERTER_PACO` | `Optional[int]` | `rw` | `None` | AC power rating of the inverter. [W] | -| pvforecast2_modules_per_string | `EOS_PVFORECAST__PVFORECAST2_MODULES_PER_STRING` | `Optional[int]` | `rw` | `None` | Number of the PV modules of the strings of this plane. | -| pvforecast2_strings_per_inverter | `EOS_PVFORECAST__PVFORECAST2_STRINGS_PER_INVERTER` | `Optional[int]` | `rw` | `None` | Number of the strings of the inverter of this plane. | -| pvforecast3_surface_tilt | `EOS_PVFORECAST__PVFORECAST3_SURFACE_TILT` | `Optional[float]` | `rw` | `None` | Tilt angle from horizontal plane. Ignored for two-axis tracking. | -| pvforecast3_surface_azimuth | `EOS_PVFORECAST__PVFORECAST3_SURFACE_AZIMUTH` | `Optional[float]` | `rw` | `None` | Orientation (azimuth angle) of the (fixed) plane. Clockwise from north (north=0, east=90, south=180, west=270). | -| pvforecast3_userhorizon | `EOS_PVFORECAST__PVFORECAST3_USERHORIZON` | `Optional[List[float]]` | `rw` | `None` | Elevation of horizon in degrees, at equally spaced azimuth clockwise from north. | -| pvforecast3_peakpower | `EOS_PVFORECAST__PVFORECAST3_PEAKPOWER` | `Optional[float]` | `rw` | `None` | Nominal power of PV system in kW. | -| pvforecast3_pvtechchoice | `EOS_PVFORECAST__PVFORECAST3_PVTECHCHOICE` | `Optional[str]` | `rw` | `crystSi` | PV technology. One of 'crystSi', 'CIS', 'CdTe', 'Unknown'. | -| pvforecast3_mountingplace | `EOS_PVFORECAST__PVFORECAST3_MOUNTINGPLACE` | `Optional[str]` | `rw` | `free` | Type of mounting for PV system. Options are 'free' for free-standing and 'building' for building-integrated. | -| pvforecast3_loss | `EOS_PVFORECAST__PVFORECAST3_LOSS` | `Optional[float]` | `rw` | `14.0` | Sum of PV system losses in percent | -| pvforecast3_trackingtype | `EOS_PVFORECAST__PVFORECAST3_TRACKINGTYPE` | `Optional[int]` | `rw` | `None` | Type of suntracking. 0=fixed, 1=single horizontal axis aligned north-south, 2=two-axis tracking, 3=vertical axis tracking, 4=single horizontal axis aligned east-west, 5=single inclined axis aligned north-south. | -| pvforecast3_optimal_surface_tilt | `EOS_PVFORECAST__PVFORECAST3_OPTIMAL_SURFACE_TILT` | `Optional[bool]` | `rw` | `False` | Calculate the optimum tilt angle. Ignored for two-axis tracking. | -| pvforecast3_optimalangles | `EOS_PVFORECAST__PVFORECAST3_OPTIMALANGLES` | `Optional[bool]` | `rw` | `False` | Calculate the optimum tilt and azimuth angles. Ignored for two-axis tracking. | -| pvforecast3_albedo | `EOS_PVFORECAST__PVFORECAST3_ALBEDO` | `Optional[float]` | `rw` | `None` | Proportion of the light hitting the ground that it reflects back. | -| pvforecast3_module_model | `EOS_PVFORECAST__PVFORECAST3_MODULE_MODEL` | `Optional[str]` | `rw` | `None` | Model of the PV modules of this plane. | -| pvforecast3_inverter_model | `EOS_PVFORECAST__PVFORECAST3_INVERTER_MODEL` | `Optional[str]` | `rw` | `None` | Model of the inverter of this plane. | -| pvforecast3_inverter_paco | `EOS_PVFORECAST__PVFORECAST3_INVERTER_PACO` | `Optional[int]` | `rw` | `None` | AC power rating of the inverter. [W] | -| pvforecast3_modules_per_string | `EOS_PVFORECAST__PVFORECAST3_MODULES_PER_STRING` | `Optional[int]` | `rw` | `None` | Number of the PV modules of the strings of this plane. | -| pvforecast3_strings_per_inverter | `EOS_PVFORECAST__PVFORECAST3_STRINGS_PER_INVERTER` | `Optional[int]` | `rw` | `None` | Number of the strings of the inverter of this plane. | -| pvforecast4_surface_tilt | `EOS_PVFORECAST__PVFORECAST4_SURFACE_TILT` | `Optional[float]` | `rw` | `None` | Tilt angle from horizontal plane. Ignored for two-axis tracking. | -| pvforecast4_surface_azimuth | `EOS_PVFORECAST__PVFORECAST4_SURFACE_AZIMUTH` | `Optional[float]` | `rw` | `None` | Orientation (azimuth angle) of the (fixed) plane. Clockwise from north (north=0, east=90, south=180, west=270). | -| pvforecast4_userhorizon | `EOS_PVFORECAST__PVFORECAST4_USERHORIZON` | `Optional[List[float]]` | `rw` | `None` | Elevation of horizon in degrees, at equally spaced azimuth clockwise from north. | -| pvforecast4_peakpower | `EOS_PVFORECAST__PVFORECAST4_PEAKPOWER` | `Optional[float]` | `rw` | `None` | Nominal power of PV system in kW. | -| pvforecast4_pvtechchoice | `EOS_PVFORECAST__PVFORECAST4_PVTECHCHOICE` | `Optional[str]` | `rw` | `crystSi` | PV technology. One of 'crystSi', 'CIS', 'CdTe', 'Unknown'. | -| pvforecast4_mountingplace | `EOS_PVFORECAST__PVFORECAST4_MOUNTINGPLACE` | `Optional[str]` | `rw` | `free` | Type of mounting for PV system. Options are 'free' for free-standing and 'building' for building-integrated. | -| pvforecast4_loss | `EOS_PVFORECAST__PVFORECAST4_LOSS` | `Optional[float]` | `rw` | `14.0` | Sum of PV system losses in percent | -| pvforecast4_trackingtype | `EOS_PVFORECAST__PVFORECAST4_TRACKINGTYPE` | `Optional[int]` | `rw` | `None` | Type of suntracking. 0=fixed, 1=single horizontal axis aligned north-south, 2=two-axis tracking, 3=vertical axis tracking, 4=single horizontal axis aligned east-west, 5=single inclined axis aligned north-south. | -| pvforecast4_optimal_surface_tilt | `EOS_PVFORECAST__PVFORECAST4_OPTIMAL_SURFACE_TILT` | `Optional[bool]` | `rw` | `False` | Calculate the optimum tilt angle. Ignored for two-axis tracking. | -| pvforecast4_optimalangles | `EOS_PVFORECAST__PVFORECAST4_OPTIMALANGLES` | `Optional[bool]` | `rw` | `False` | Calculate the optimum tilt and azimuth angles. Ignored for two-axis tracking. | -| pvforecast4_albedo | `EOS_PVFORECAST__PVFORECAST4_ALBEDO` | `Optional[float]` | `rw` | `None` | Proportion of the light hitting the ground that it reflects back. | -| pvforecast4_module_model | `EOS_PVFORECAST__PVFORECAST4_MODULE_MODEL` | `Optional[str]` | `rw` | `None` | Model of the PV modules of this plane. | -| pvforecast4_inverter_model | `EOS_PVFORECAST__PVFORECAST4_INVERTER_MODEL` | `Optional[str]` | `rw` | `None` | Model of the inverter of this plane. | -| pvforecast4_inverter_paco | `EOS_PVFORECAST__PVFORECAST4_INVERTER_PACO` | `Optional[int]` | `rw` | `None` | AC power rating of the inverter. [W] | -| pvforecast4_modules_per_string | `EOS_PVFORECAST__PVFORECAST4_MODULES_PER_STRING` | `Optional[int]` | `rw` | `None` | Number of the PV modules of the strings of this plane. | -| pvforecast4_strings_per_inverter | `EOS_PVFORECAST__PVFORECAST4_STRINGS_PER_INVERTER` | `Optional[int]` | `rw` | `None` | Number of the strings of the inverter of this plane. | -| pvforecast5_surface_tilt | `EOS_PVFORECAST__PVFORECAST5_SURFACE_TILT` | `Optional[float]` | `rw` | `None` | Tilt angle from horizontal plane. Ignored for two-axis tracking. | -| pvforecast5_surface_azimuth | `EOS_PVFORECAST__PVFORECAST5_SURFACE_AZIMUTH` | `Optional[float]` | `rw` | `None` | Orientation (azimuth angle) of the (fixed) plane. Clockwise from north (north=0, east=90, south=180, west=270). | -| pvforecast5_userhorizon | `EOS_PVFORECAST__PVFORECAST5_USERHORIZON` | `Optional[List[float]]` | `rw` | `None` | Elevation of horizon in degrees, at equally spaced azimuth clockwise from north. | -| pvforecast5_peakpower | `EOS_PVFORECAST__PVFORECAST5_PEAKPOWER` | `Optional[float]` | `rw` | `None` | Nominal power of PV system in kW. | -| pvforecast5_pvtechchoice | `EOS_PVFORECAST__PVFORECAST5_PVTECHCHOICE` | `Optional[str]` | `rw` | `crystSi` | PV technology. One of 'crystSi', 'CIS', 'CdTe', 'Unknown'. | -| pvforecast5_mountingplace | `EOS_PVFORECAST__PVFORECAST5_MOUNTINGPLACE` | `Optional[str]` | `rw` | `free` | Type of mounting for PV system. Options are 'free' for free-standing and 'building' for building-integrated. | -| pvforecast5_loss | `EOS_PVFORECAST__PVFORECAST5_LOSS` | `Optional[float]` | `rw` | `14.0` | Sum of PV system losses in percent | -| pvforecast5_trackingtype | `EOS_PVFORECAST__PVFORECAST5_TRACKINGTYPE` | `Optional[int]` | `rw` | `None` | Type of suntracking. 0=fixed, 1=single horizontal axis aligned north-south, 2=two-axis tracking, 3=vertical axis tracking, 4=single horizontal axis aligned east-west, 5=single inclined axis aligned north-south. | -| pvforecast5_optimal_surface_tilt | `EOS_PVFORECAST__PVFORECAST5_OPTIMAL_SURFACE_TILT` | `Optional[bool]` | `rw` | `False` | Calculate the optimum tilt angle. Ignored for two-axis tracking. | -| pvforecast5_optimalangles | `EOS_PVFORECAST__PVFORECAST5_OPTIMALANGLES` | `Optional[bool]` | `rw` | `False` | Calculate the optimum tilt and azimuth angles. Ignored for two-axis tracking. | -| pvforecast5_albedo | `EOS_PVFORECAST__PVFORECAST5_ALBEDO` | `Optional[float]` | `rw` | `None` | Proportion of the light hitting the ground that it reflects back. | -| pvforecast5_module_model | `EOS_PVFORECAST__PVFORECAST5_MODULE_MODEL` | `Optional[str]` | `rw` | `None` | Model of the PV modules of this plane. | -| pvforecast5_inverter_model | `EOS_PVFORECAST__PVFORECAST5_INVERTER_MODEL` | `Optional[str]` | `rw` | `None` | Model of the inverter of this plane. | -| pvforecast5_inverter_paco | `EOS_PVFORECAST__PVFORECAST5_INVERTER_PACO` | `Optional[int]` | `rw` | `None` | AC power rating of the inverter. [W] | -| pvforecast5_modules_per_string | `EOS_PVFORECAST__PVFORECAST5_MODULES_PER_STRING` | `Optional[int]` | `rw` | `None` | Number of the PV modules of the strings of this plane. | -| pvforecast5_strings_per_inverter | `EOS_PVFORECAST__PVFORECAST5_STRINGS_PER_INVERTER` | `Optional[int]` | `rw` | `None` | Number of the strings of the inverter of this plane. | +| planes | `EOS_PVFORECAST__PLANES` | `Optional[list[akkudoktoreos.prediction.pvforecast.PVForecastPlaneSetting]]` | `rw` | `None` | Plane configuration. | | provider_settings | `EOS_PVFORECAST__PROVIDER_SETTINGS` | `Optional[akkudoktoreos.prediction.pvforecastimport.PVForecastImportCommonSettings]` | `rw` | `None` | Provider settings | -| pvforecast_planes | | `List[str]` | `ro` | `N/A` | Compute a list of active planes. | -| pvforecast_planes_peakpower | | `List[float]` | `ro` | `N/A` | Compute a list of the peak power per active planes. | -| pvforecast_planes_azimuth | | `List[float]` | `ro` | `N/A` | Compute a list of the azimuths per active planes. | -| pvforecast_planes_tilt | | `List[float]` | `ro` | `N/A` | Compute a list of the tilts per active planes. | -| pvforecast_planes_userhorizon | | `Any` | `ro` | `N/A` | Compute a list of the user horizon per active planes. | -| pvforecast_planes_inverter_paco | | `Any` | `ro` | `N/A` | Compute a list of the maximum power rating of the inverter per active planes. | +| planes_peakpower | | `List[float]` | `ro` | `N/A` | Compute a list of the peak power per active planes. | +| planes_azimuth | | `List[float]` | `ro` | `N/A` | Compute a list of the azimuths per active planes. | +| planes_tilt | | `List[float]` | `ro` | `N/A` | Compute a list of the tilts per active planes. | +| planes_userhorizon | | `Any` | `ro` | `N/A` | Compute a list of the user horizon per active planes. | +| planes_inverter_paco | | `Any` | `ro` | `N/A` | Compute a list of the maximum power rating of the inverter per active planes. | ::: ### Example Input @@ -623,110 +527,52 @@ Validators: { "pvforecast": { "provider": "PVForecastAkkudoktor", - "pvforecast0_surface_tilt": 10.0, - "pvforecast0_surface_azimuth": 10.0, - "pvforecast0_userhorizon": [ - 10.0, - 20.0, - 30.0 + "planes": [ + { + "surface_tilt": 10.0, + "surface_azimuth": 10.0, + "userhorizon": [ + 10.0, + 20.0, + 30.0 + ], + "peakpower": 5.0, + "pvtechchoice": "crystSi", + "mountingplace": "free", + "loss": 14.0, + "trackingtype": 0, + "optimal_surface_tilt": false, + "optimalangles": false, + "albedo": null, + "module_model": null, + "inverter_model": null, + "inverter_paco": 6000, + "modules_per_string": 20, + "strings_per_inverter": 2 + }, + { + "surface_tilt": 20.0, + "surface_azimuth": 20.0, + "userhorizon": [ + 5.0, + 15.0, + 25.0 + ], + "peakpower": 3.5, + "pvtechchoice": "crystSi", + "mountingplace": "free", + "loss": 14.0, + "trackingtype": 1, + "optimal_surface_tilt": false, + "optimalangles": false, + "albedo": null, + "module_model": null, + "inverter_model": null, + "inverter_paco": 4000, + "modules_per_string": 20, + "strings_per_inverter": 2 + } ], - "pvforecast0_peakpower": 5.0, - "pvforecast0_pvtechchoice": "crystSi", - "pvforecast0_mountingplace": "free", - "pvforecast0_loss": 14.0, - "pvforecast0_trackingtype": 0, - "pvforecast0_optimal_surface_tilt": false, - "pvforecast0_optimalangles": false, - "pvforecast0_albedo": null, - "pvforecast0_module_model": null, - "pvforecast0_inverter_model": null, - "pvforecast0_inverter_paco": 6000, - "pvforecast0_modules_per_string": 20, - "pvforecast0_strings_per_inverter": 2, - "pvforecast1_surface_tilt": 20.0, - "pvforecast1_surface_azimuth": 20.0, - "pvforecast1_userhorizon": [ - 5.0, - 15.0, - 25.0 - ], - "pvforecast1_peakpower": 3.5, - "pvforecast1_pvtechchoice": "crystSi", - "pvforecast1_mountingplace": "free", - "pvforecast1_loss": 14.0, - "pvforecast1_trackingtype": null, - "pvforecast1_optimal_surface_tilt": false, - "pvforecast1_optimalangles": false, - "pvforecast1_albedo": null, - "pvforecast1_module_model": null, - "pvforecast1_inverter_model": null, - "pvforecast1_inverter_paco": 4000, - "pvforecast1_modules_per_string": 20, - "pvforecast1_strings_per_inverter": 2, - "pvforecast2_surface_tilt": null, - "pvforecast2_surface_azimuth": null, - "pvforecast2_userhorizon": null, - "pvforecast2_peakpower": null, - "pvforecast2_pvtechchoice": null, - "pvforecast2_mountingplace": null, - "pvforecast2_loss": null, - "pvforecast2_trackingtype": null, - "pvforecast2_optimal_surface_tilt": null, - "pvforecast2_optimalangles": null, - "pvforecast2_albedo": null, - "pvforecast2_module_model": null, - "pvforecast2_inverter_model": null, - "pvforecast2_inverter_paco": null, - "pvforecast2_modules_per_string": null, - "pvforecast2_strings_per_inverter": null, - "pvforecast3_surface_tilt": null, - "pvforecast3_surface_azimuth": null, - "pvforecast3_userhorizon": null, - "pvforecast3_peakpower": null, - "pvforecast3_pvtechchoice": null, - "pvforecast3_mountingplace": null, - "pvforecast3_loss": null, - "pvforecast3_trackingtype": null, - "pvforecast3_optimal_surface_tilt": null, - "pvforecast3_optimalangles": null, - "pvforecast3_albedo": null, - "pvforecast3_module_model": null, - "pvforecast3_inverter_model": null, - "pvforecast3_inverter_paco": null, - "pvforecast3_modules_per_string": null, - "pvforecast3_strings_per_inverter": null, - "pvforecast4_surface_tilt": null, - "pvforecast4_surface_azimuth": null, - "pvforecast4_userhorizon": null, - "pvforecast4_peakpower": null, - "pvforecast4_pvtechchoice": null, - "pvforecast4_mountingplace": null, - "pvforecast4_loss": null, - "pvforecast4_trackingtype": null, - "pvforecast4_optimal_surface_tilt": null, - "pvforecast4_optimalangles": null, - "pvforecast4_albedo": null, - "pvforecast4_module_model": null, - "pvforecast4_inverter_model": null, - "pvforecast4_inverter_paco": null, - "pvforecast4_modules_per_string": null, - "pvforecast4_strings_per_inverter": null, - "pvforecast5_surface_tilt": null, - "pvforecast5_surface_azimuth": null, - "pvforecast5_userhorizon": null, - "pvforecast5_peakpower": null, - "pvforecast5_pvtechchoice": null, - "pvforecast5_mountingplace": null, - "pvforecast5_loss": null, - "pvforecast5_trackingtype": null, - "pvforecast5_optimal_surface_tilt": null, - "pvforecast5_optimalangles": null, - "pvforecast5_albedo": null, - "pvforecast5_module_model": null, - "pvforecast5_inverter_model": null, - "pvforecast5_inverter_paco": null, - "pvforecast5_modules_per_string": null, - "pvforecast5_strings_per_inverter": null, "provider_settings": null } } @@ -740,128 +586,66 @@ Validators: { "pvforecast": { "provider": "PVForecastAkkudoktor", - "pvforecast0_surface_tilt": 10.0, - "pvforecast0_surface_azimuth": 10.0, - "pvforecast0_userhorizon": [ - 10.0, - 20.0, - 30.0 + "planes": [ + { + "surface_tilt": 10.0, + "surface_azimuth": 10.0, + "userhorizon": [ + 10.0, + 20.0, + 30.0 + ], + "peakpower": 5.0, + "pvtechchoice": "crystSi", + "mountingplace": "free", + "loss": 14.0, + "trackingtype": 0, + "optimal_surface_tilt": false, + "optimalangles": false, + "albedo": null, + "module_model": null, + "inverter_model": null, + "inverter_paco": 6000, + "modules_per_string": 20, + "strings_per_inverter": 2 + }, + { + "surface_tilt": 20.0, + "surface_azimuth": 20.0, + "userhorizon": [ + 5.0, + 15.0, + 25.0 + ], + "peakpower": 3.5, + "pvtechchoice": "crystSi", + "mountingplace": "free", + "loss": 14.0, + "trackingtype": 1, + "optimal_surface_tilt": false, + "optimalangles": false, + "albedo": null, + "module_model": null, + "inverter_model": null, + "inverter_paco": 4000, + "modules_per_string": 20, + "strings_per_inverter": 2 + } ], - "pvforecast0_peakpower": 5.0, - "pvforecast0_pvtechchoice": "crystSi", - "pvforecast0_mountingplace": "free", - "pvforecast0_loss": 14.0, - "pvforecast0_trackingtype": 0, - "pvforecast0_optimal_surface_tilt": false, - "pvforecast0_optimalangles": false, - "pvforecast0_albedo": null, - "pvforecast0_module_model": null, - "pvforecast0_inverter_model": null, - "pvforecast0_inverter_paco": 6000, - "pvforecast0_modules_per_string": 20, - "pvforecast0_strings_per_inverter": 2, - "pvforecast1_surface_tilt": 20.0, - "pvforecast1_surface_azimuth": 20.0, - "pvforecast1_userhorizon": [ - 5.0, - 15.0, - 25.0 - ], - "pvforecast1_peakpower": 3.5, - "pvforecast1_pvtechchoice": "crystSi", - "pvforecast1_mountingplace": "free", - "pvforecast1_loss": 14.0, - "pvforecast1_trackingtype": null, - "pvforecast1_optimal_surface_tilt": false, - "pvforecast1_optimalangles": false, - "pvforecast1_albedo": null, - "pvforecast1_module_model": null, - "pvforecast1_inverter_model": null, - "pvforecast1_inverter_paco": 4000, - "pvforecast1_modules_per_string": 20, - "pvforecast1_strings_per_inverter": 2, - "pvforecast2_surface_tilt": null, - "pvforecast2_surface_azimuth": null, - "pvforecast2_userhorizon": null, - "pvforecast2_peakpower": null, - "pvforecast2_pvtechchoice": null, - "pvforecast2_mountingplace": null, - "pvforecast2_loss": null, - "pvforecast2_trackingtype": null, - "pvforecast2_optimal_surface_tilt": null, - "pvforecast2_optimalangles": null, - "pvforecast2_albedo": null, - "pvforecast2_module_model": null, - "pvforecast2_inverter_model": null, - "pvforecast2_inverter_paco": null, - "pvforecast2_modules_per_string": null, - "pvforecast2_strings_per_inverter": null, - "pvforecast3_surface_tilt": null, - "pvforecast3_surface_azimuth": null, - "pvforecast3_userhorizon": null, - "pvforecast3_peakpower": null, - "pvforecast3_pvtechchoice": null, - "pvforecast3_mountingplace": null, - "pvforecast3_loss": null, - "pvforecast3_trackingtype": null, - "pvforecast3_optimal_surface_tilt": null, - "pvforecast3_optimalangles": null, - "pvforecast3_albedo": null, - "pvforecast3_module_model": null, - "pvforecast3_inverter_model": null, - "pvforecast3_inverter_paco": null, - "pvforecast3_modules_per_string": null, - "pvforecast3_strings_per_inverter": null, - "pvforecast4_surface_tilt": null, - "pvforecast4_surface_azimuth": null, - "pvforecast4_userhorizon": null, - "pvforecast4_peakpower": null, - "pvforecast4_pvtechchoice": null, - "pvforecast4_mountingplace": null, - "pvforecast4_loss": null, - "pvforecast4_trackingtype": null, - "pvforecast4_optimal_surface_tilt": null, - "pvforecast4_optimalangles": null, - "pvforecast4_albedo": null, - "pvforecast4_module_model": null, - "pvforecast4_inverter_model": null, - "pvforecast4_inverter_paco": null, - "pvforecast4_modules_per_string": null, - "pvforecast4_strings_per_inverter": null, - "pvforecast5_surface_tilt": null, - "pvforecast5_surface_azimuth": null, - "pvforecast5_userhorizon": null, - "pvforecast5_peakpower": null, - "pvforecast5_pvtechchoice": null, - "pvforecast5_mountingplace": null, - "pvforecast5_loss": null, - "pvforecast5_trackingtype": null, - "pvforecast5_optimal_surface_tilt": null, - "pvforecast5_optimalangles": null, - "pvforecast5_albedo": null, - "pvforecast5_module_model": null, - "pvforecast5_inverter_model": null, - "pvforecast5_inverter_paco": null, - "pvforecast5_modules_per_string": null, - "pvforecast5_strings_per_inverter": null, "provider_settings": null, - "pvforecast_planes": [ - "pvforecast0", - "pvforecast1" - ], - "pvforecast_planes_peakpower": [ + "planes_peakpower": [ 5.0, 3.5 ], - "pvforecast_planes_azimuth": [ + "planes_azimuth": [ 10.0, 20.0 ], - "pvforecast_planes_tilt": [ + "planes_tilt": [ 10.0, 20.0 ], - "pvforecast_planes_userhorizon": [ + "planes_userhorizon": [ [ 10.0, 20.0, @@ -873,7 +657,7 @@ Validators: 25.0 ] ], - "pvforecast_planes_inverter_paco": [ + "planes_inverter_paco": [ 6000.0, 4000.0 ] @@ -889,8 +673,8 @@ Validators: | Name | Type | Read-Only | Default | Description | | ---- | ---- | --------- | ------- | ----------- | -| pvforecastimport_file_path | `Union[str, pathlib.Path, NoneType]` | `rw` | `None` | Path to the file to import PV forecast data from. | -| pvforecastimport_json | `Optional[str]` | `rw` | `None` | JSON string, dictionary of PV forecast value lists. | +| import_file_path | `Union[str, pathlib.Path, NoneType]` | `rw` | `None` | Path to the file to import PV forecast data from. | +| import_json | `Optional[str]` | `rw` | `None` | JSON string, dictionary of PV forecast value lists. | ::: #### Example Input/Output @@ -901,13 +685,96 @@ Validators: { "pvforecast": { "provider_settings": { - "pvforecastimport_file_path": null, - "pvforecastimport_json": "{\"pvforecast_ac_power\": [0, 8.05, 352.91]}" + "import_file_path": null, + "import_json": "{\"pvforecast_ac_power\": [0, 8.05, 352.91]}" } } } ``` +### PV Forecast Plane Configuration + +:::{table} pvforecast::planes::list +:widths: 10 10 5 5 30 +:align: left + +| Name | Type | Read-Only | Default | Description | +| ---- | ---- | --------- | ------- | ----------- | +| surface_tilt | `Optional[float]` | `rw` | `None` | Tilt angle from horizontal plane. Ignored for two-axis tracking. | +| surface_azimuth | `Optional[float]` | `rw` | `None` | Orientation (azimuth angle) of the (fixed) plane. Clockwise from north (north=0, east=90, south=180, west=270). | +| userhorizon | `Optional[List[float]]` | `rw` | `None` | Elevation of horizon in degrees, at equally spaced azimuth clockwise from north. | +| peakpower | `Optional[float]` | `rw` | `None` | Nominal power of PV system in kW. | +| pvtechchoice | `Optional[str]` | `rw` | `crystSi` | PV technology. One of 'crystSi', 'CIS', 'CdTe', 'Unknown'. | +| mountingplace | `Optional[str]` | `rw` | `free` | Type of mounting for PV system. Options are 'free' for free-standing and 'building' for building-integrated. | +| loss | `Optional[float]` | `rw` | `14.0` | Sum of PV system losses in percent | +| trackingtype | `Optional[int]` | `rw` | `None` | Type of suntracking. 0=fixed, 1=single horizontal axis aligned north-south, 2=two-axis tracking, 3=vertical axis tracking, 4=single horizontal axis aligned east-west, 5=single inclined axis aligned north-south. | +| optimal_surface_tilt | `Optional[bool]` | `rw` | `False` | Calculate the optimum tilt angle. Ignored for two-axis tracking. | +| optimalangles | `Optional[bool]` | `rw` | `False` | Calculate the optimum tilt and azimuth angles. Ignored for two-axis tracking. | +| albedo | `Optional[float]` | `rw` | `None` | Proportion of the light hitting the ground that it reflects back. | +| module_model | `Optional[str]` | `rw` | `None` | Model of the PV modules of this plane. | +| inverter_model | `Optional[str]` | `rw` | `None` | Model of the inverter of this plane. | +| inverter_paco | `Optional[int]` | `rw` | `None` | AC power rating of the inverter. [W] | +| modules_per_string | `Optional[int]` | `rw` | `None` | Number of the PV modules of the strings of this plane. | +| strings_per_inverter | `Optional[int]` | `rw` | `None` | Number of the strings of the inverter of this plane. | +::: + +#### Example Input/Output + +```{eval-rst} +.. code-block:: json + + { + "pvforecast": { + "planes": [ + { + "surface_tilt": 10.0, + "surface_azimuth": 10.0, + "userhorizon": [ + 10.0, + 20.0, + 30.0 + ], + "peakpower": 5.0, + "pvtechchoice": "crystSi", + "mountingplace": "free", + "loss": 14.0, + "trackingtype": 0, + "optimal_surface_tilt": false, + "optimalangles": false, + "albedo": null, + "module_model": null, + "inverter_model": null, + "inverter_paco": 6000, + "modules_per_string": 20, + "strings_per_inverter": 2 + }, + { + "surface_tilt": 20.0, + "surface_azimuth": 20.0, + "userhorizon": [ + 5.0, + 15.0, + 25.0 + ], + "peakpower": 3.5, + "pvtechchoice": "crystSi", + "mountingplace": "free", + "loss": 14.0, + "trackingtype": 1, + "optimal_surface_tilt": false, + "optimalangles": false, + "albedo": null, + "module_model": null, + "inverter_model": null, + "inverter_paco": 4000, + "modules_per_string": 20, + "strings_per_inverter": 2 + } + ] + } + } +``` + ## Weather Forecast Configuration :::{table} weather diff --git a/docs/akkudoktoreos/prediction.md b/docs/akkudoktoreos/prediction.md index 4a2a4ff..e8234e5 100644 --- a/docs/akkudoktoreos/prediction.md +++ b/docs/akkudoktoreos/prediction.md @@ -211,8 +211,8 @@ Configuration options: - `pvforecast<0..5>_inverter_paco`: AC power rating of the inverter. [W] - `pvforecast<0..5>_modules_per_string`: Number of the PV modules of the strings of this plane. - `pvforecast<0..5>_strings_per_inverter`: Number of the strings of the inverter of this plane. -- `pvforecastimport_file_path`: Path to the file to import PV forecast data from. -- `pvforecastimport_json`: JSON string, dictionary of PV forecast value lists. +- `import_file_path`: Path to the file to import PV forecast data from. +- `import_json`: JSON string, dictionary of PV forecast value lists. ------ @@ -337,7 +337,7 @@ The prediction keys for the PV forecast data are: The PV forecast data must be provided in one of the formats described in . The data source must be given in the -`pvforecastimport_file_path` or `pvforecastimport_json` configuration option. +`import_file_path` or `import_json` configuration option. ## Weather Prediction @@ -459,4 +459,4 @@ The prediction keys for the PV forecast data are: The PV forecast data must be provided in one of the formats described in . The data source must be given in the -`import_file_path` or `pvforecastimport_json` configuration option. +`import_file_path` or `import_json` configuration option. diff --git a/openapi.json b/openapi.json index 9c775de..8e002ad 100644 --- a/openapi.json +++ b/openapi.json @@ -304,42 +304,11 @@ "pvforecast": { "$ref": "#/components/schemas/PVForecastCommonSettings-Output", "default": { - "pvforecast0_loss": 14.0, - "pvforecast0_mountingplace": "free", - "pvforecast0_optimal_surface_tilt": false, - "pvforecast0_optimalangles": false, - "pvforecast0_pvtechchoice": "crystSi", - "pvforecast1_loss": 14.0, - "pvforecast1_mountingplace": "free", - "pvforecast1_optimal_surface_tilt": false, - "pvforecast1_optimalangles": false, - "pvforecast1_pvtechchoice": "crystSi", - "pvforecast2_loss": 14.0, - "pvforecast2_mountingplace": "free", - "pvforecast2_optimal_surface_tilt": false, - "pvforecast2_optimalangles": false, - "pvforecast2_pvtechchoice": "crystSi", - "pvforecast3_loss": 14.0, - "pvforecast3_mountingplace": "free", - "pvforecast3_optimal_surface_tilt": false, - "pvforecast3_optimalangles": false, - "pvforecast3_pvtechchoice": "crystSi", - "pvforecast4_loss": 14.0, - "pvforecast4_mountingplace": "free", - "pvforecast4_optimal_surface_tilt": false, - "pvforecast4_optimalangles": false, - "pvforecast4_pvtechchoice": "crystSi", - "pvforecast5_loss": 14.0, - "pvforecast5_mountingplace": "free", - "pvforecast5_optimal_surface_tilt": false, - "pvforecast5_optimalangles": false, - "pvforecast5_pvtechchoice": "crystSi", - "pvforecast_planes": [], - "pvforecast_planes_azimuth": [], - "pvforecast_planes_inverter_paco": [], - "pvforecast_planes_peakpower": [], - "pvforecast_planes_tilt": [], - "pvforecast_planes_userhorizon": [] + "planes_azimuth": [], + "planes_inverter_paco": [], + "planes_peakpower": [], + "planes_tilt": [], + "planes_userhorizon": [] } }, "server": { @@ -1453,6 +1422,63 @@ "PVForecastCommonSettings-Input": { "description": "PV Forecast Configuration.", "properties": { + "planes": { + "anyOf": [ + { + "items": { + "$ref": "#/components/schemas/PVForecastPlaneSetting" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "description": "Plane configuration.", + "examples": [ + [ + { + "inverter_paco": 6000, + "loss": 14.0, + "modules_per_string": 20, + "mountingplace": "free", + "optimal_surface_tilt": false, + "optimalangles": false, + "peakpower": 5.0, + "pvtechchoice": "crystSi", + "strings_per_inverter": 2, + "surface_azimuth": 10.0, + "surface_tilt": 10.0, + "trackingtype": 0, + "userhorizon": [ + 10.0, + 20.0, + 30.0 + ] + }, + { + "inverter_paco": 4000, + "loss": 14.0, + "modules_per_string": 20, + "mountingplace": "free", + "optimal_surface_tilt": false, + "optimalangles": false, + "peakpower": 3.5, + "pvtechchoice": "crystSi", + "strings_per_inverter": 2, + "surface_azimuth": 20.0, + "surface_tilt": 20.0, + "trackingtype": 1, + "userhorizon": [ + 5.0, + 15.0, + 25.0 + ] + } + ] + ], + "title": "Planes" + }, "provider": { "anyOf": [ { @@ -1481,1489 +1507,6 @@ "examples": [ null ] - }, - "pvforecast0_albedo": { - "anyOf": [ - { - "type": "number" - }, - { - "type": "null" - } - ], - "description": "Proportion of the light hitting the ground that it reflects back.", - "examples": [ - null - ], - "title": "Pvforecast0 Albedo" - }, - "pvforecast0_inverter_model": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "description": "Model of the inverter of this plane.", - "examples": [ - null - ], - "title": "Pvforecast0 Inverter Model" - }, - "pvforecast0_inverter_paco": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "description": "AC power rating of the inverter. [W]", - "examples": [ - 6000 - ], - "title": "Pvforecast0 Inverter Paco" - }, - "pvforecast0_loss": { - "anyOf": [ - { - "type": "number" - }, - { - "type": "null" - } - ], - "default": 14.0, - "description": "Sum of PV system losses in percent", - "title": "Pvforecast0 Loss" - }, - "pvforecast0_module_model": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "description": "Model of the PV modules of this plane.", - "examples": [ - null - ], - "title": "Pvforecast0 Module Model" - }, - "pvforecast0_modules_per_string": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "description": "Number of the PV modules of the strings of this plane.", - "examples": [ - 20 - ], - "title": "Pvforecast0 Modules Per String" - }, - "pvforecast0_mountingplace": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "default": "free", - "description": "Type of mounting for PV system. Options are 'free' for free-standing and 'building' for building-integrated.", - "title": "Pvforecast0 Mountingplace" - }, - "pvforecast0_optimal_surface_tilt": { - "anyOf": [ - { - "type": "boolean" - }, - { - "type": "null" - } - ], - "default": false, - "description": "Calculate the optimum tilt angle. Ignored for two-axis tracking.", - "examples": [ - false - ], - "title": "Pvforecast0 Optimal Surface Tilt" - }, - "pvforecast0_optimalangles": { - "anyOf": [ - { - "type": "boolean" - }, - { - "type": "null" - } - ], - "default": false, - "description": "Calculate the optimum tilt and azimuth angles. Ignored for two-axis tracking.", - "examples": [ - false - ], - "title": "Pvforecast0 Optimalangles" - }, - "pvforecast0_peakpower": { - "anyOf": [ - { - "type": "number" - }, - { - "type": "null" - } - ], - "description": "Nominal power of PV system in kW.", - "examples": [ - 5.0 - ], - "title": "Pvforecast0 Peakpower" - }, - "pvforecast0_pvtechchoice": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "default": "crystSi", - "description": "PV technology. One of 'crystSi', 'CIS', 'CdTe', 'Unknown'.", - "title": "Pvforecast0 Pvtechchoice" - }, - "pvforecast0_strings_per_inverter": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "description": "Number of the strings of the inverter of this plane.", - "examples": [ - 2 - ], - "title": "Pvforecast0 Strings Per Inverter" - }, - "pvforecast0_surface_azimuth": { - "anyOf": [ - { - "type": "number" - }, - { - "type": "null" - } - ], - "description": "Orientation (azimuth angle) of the (fixed) plane. Clockwise from north (north=0, east=90, south=180, west=270).", - "examples": [ - 10.0 - ], - "title": "Pvforecast0 Surface Azimuth" - }, - "pvforecast0_surface_tilt": { - "anyOf": [ - { - "type": "number" - }, - { - "type": "null" - } - ], - "description": "Tilt angle from horizontal plane. Ignored for two-axis tracking.", - "examples": [ - 10.0 - ], - "title": "Pvforecast0 Surface Tilt" - }, - "pvforecast0_trackingtype": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "description": "Type of suntracking. 0=fixed, 1=single horizontal axis aligned north-south, 2=two-axis tracking, 3=vertical axis tracking, 4=single horizontal axis aligned east-west, 5=single inclined axis aligned north-south.", - "examples": [ - 0, - 1, - 2, - 3, - 4, - 5 - ], - "title": "Pvforecast0 Trackingtype" - }, - "pvforecast0_userhorizon": { - "anyOf": [ - { - "items": { - "type": "number" - }, - "type": "array" - }, - { - "type": "null" - } - ], - "description": "Elevation of horizon in degrees, at equally spaced azimuth clockwise from north.", - "examples": [ - [ - 10.0, - 20.0, - 30.0 - ] - ], - "title": "Pvforecast0 Userhorizon" - }, - "pvforecast1_albedo": { - "anyOf": [ - { - "type": "number" - }, - { - "type": "null" - } - ], - "description": "Proportion of the light hitting the ground that it reflects back.", - "examples": [ - null - ], - "title": "Pvforecast1 Albedo" - }, - "pvforecast1_inverter_model": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "description": "Model of the inverter of this plane.", - "examples": [ - null - ], - "title": "Pvforecast1 Inverter Model" - }, - "pvforecast1_inverter_paco": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "description": "AC power rating of the inverter. [W]", - "examples": [ - 4000 - ], - "title": "Pvforecast1 Inverter Paco" - }, - "pvforecast1_loss": { - "anyOf": [ - { - "type": "number" - }, - { - "type": "null" - } - ], - "default": 14.0, - "description": "Sum of PV system losses in percent", - "title": "Pvforecast1 Loss" - }, - "pvforecast1_module_model": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "description": "Model of the PV modules of this plane.", - "examples": [ - null - ], - "title": "Pvforecast1 Module Model" - }, - "pvforecast1_modules_per_string": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "description": "Number of the PV modules of the strings of this plane.", - "examples": [ - 20 - ], - "title": "Pvforecast1 Modules Per String" - }, - "pvforecast1_mountingplace": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "default": "free", - "description": "Type of mounting for PV system. Options are 'free' for free-standing and 'building' for building-integrated.", - "title": "Pvforecast1 Mountingplace" - }, - "pvforecast1_optimal_surface_tilt": { - "anyOf": [ - { - "type": "boolean" - }, - { - "type": "null" - } - ], - "default": false, - "description": "Calculate the optimum tilt angle. Ignored for two-axis tracking.", - "examples": [ - false - ], - "title": "Pvforecast1 Optimal Surface Tilt" - }, - "pvforecast1_optimalangles": { - "anyOf": [ - { - "type": "boolean" - }, - { - "type": "null" - } - ], - "default": false, - "description": "Calculate the optimum tilt and azimuth angles. Ignored for two-axis tracking.", - "examples": [ - false - ], - "title": "Pvforecast1 Optimalangles" - }, - "pvforecast1_peakpower": { - "anyOf": [ - { - "type": "number" - }, - { - "type": "null" - } - ], - "description": "Nominal power of PV system in kW.", - "examples": [ - 3.5 - ], - "title": "Pvforecast1 Peakpower" - }, - "pvforecast1_pvtechchoice": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "default": "crystSi", - "description": "PV technology. One of 'crystSi', 'CIS', 'CdTe', 'Unknown'.", - "title": "Pvforecast1 Pvtechchoice" - }, - "pvforecast1_strings_per_inverter": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "description": "Number of the strings of the inverter of this plane.", - "examples": [ - 2 - ], - "title": "Pvforecast1 Strings Per Inverter" - }, - "pvforecast1_surface_azimuth": { - "anyOf": [ - { - "type": "number" - }, - { - "type": "null" - } - ], - "description": "Orientation (azimuth angle) of the (fixed) plane. Clockwise from north (north=0, east=90, south=180, west=270).", - "examples": [ - 20.0 - ], - "title": "Pvforecast1 Surface Azimuth" - }, - "pvforecast1_surface_tilt": { - "anyOf": [ - { - "type": "number" - }, - { - "type": "null" - } - ], - "description": "Tilt angle from horizontal plane. Ignored for two-axis tracking.", - "examples": [ - 20.0 - ], - "title": "Pvforecast1 Surface Tilt" - }, - "pvforecast1_trackingtype": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "description": "Type of suntracking. 0=fixed, 1=single horizontal axis aligned north-south, 2=two-axis tracking, 3=vertical axis tracking, 4=single horizontal axis aligned east-west, 5=single inclined axis aligned north-south.", - "examples": [ - null - ], - "title": "Pvforecast1 Trackingtype" - }, - "pvforecast1_userhorizon": { - "anyOf": [ - { - "items": { - "type": "number" - }, - "type": "array" - }, - { - "type": "null" - } - ], - "description": "Elevation of horizon in degrees, at equally spaced azimuth clockwise from north.", - "examples": [ - [ - 5.0, - 15.0, - 25.0 - ] - ], - "title": "Pvforecast1 Userhorizon" - }, - "pvforecast2_albedo": { - "anyOf": [ - { - "type": "number" - }, - { - "type": "null" - } - ], - "description": "Proportion of the light hitting the ground that it reflects back.", - "examples": [ - null - ], - "title": "Pvforecast2 Albedo" - }, - "pvforecast2_inverter_model": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "description": "Model of the inverter of this plane.", - "examples": [ - null - ], - "title": "Pvforecast2 Inverter Model" - }, - "pvforecast2_inverter_paco": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "description": "AC power rating of the inverter. [W]", - "examples": [ - null - ], - "title": "Pvforecast2 Inverter Paco" - }, - "pvforecast2_loss": { - "anyOf": [ - { - "type": "number" - }, - { - "type": "null" - } - ], - "default": 14.0, - "description": "Sum of PV system losses in percent", - "examples": [ - null - ], - "title": "Pvforecast2 Loss" - }, - "pvforecast2_module_model": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "description": "Model of the PV modules of this plane.", - "examples": [ - null - ], - "title": "Pvforecast2 Module Model" - }, - "pvforecast2_modules_per_string": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "description": "Number of the PV modules of the strings of this plane.", - "examples": [ - null - ], - "title": "Pvforecast2 Modules Per String" - }, - "pvforecast2_mountingplace": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "default": "free", - "description": "Type of mounting for PV system. Options are 'free' for free-standing and 'building' for building-integrated.", - "examples": [ - null - ], - "title": "Pvforecast2 Mountingplace" - }, - "pvforecast2_optimal_surface_tilt": { - "anyOf": [ - { - "type": "boolean" - }, - { - "type": "null" - } - ], - "default": false, - "description": "Calculate the optimum tilt angle. Ignored for two-axis tracking.", - "examples": [ - null - ], - "title": "Pvforecast2 Optimal Surface Tilt" - }, - "pvforecast2_optimalangles": { - "anyOf": [ - { - "type": "boolean" - }, - { - "type": "null" - } - ], - "default": false, - "description": "Calculate the optimum tilt and azimuth angles. Ignored for two-axis tracking.", - "examples": [ - null - ], - "title": "Pvforecast2 Optimalangles" - }, - "pvforecast2_peakpower": { - "anyOf": [ - { - "type": "number" - }, - { - "type": "null" - } - ], - "description": "Nominal power of PV system in kW.", - "examples": [ - null - ], - "title": "Pvforecast2 Peakpower" - }, - "pvforecast2_pvtechchoice": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "default": "crystSi", - "description": "PV technology. One of 'crystSi', 'CIS', 'CdTe', 'Unknown'.", - "examples": [ - null - ], - "title": "Pvforecast2 Pvtechchoice" - }, - "pvforecast2_strings_per_inverter": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "description": "Number of the strings of the inverter of this plane.", - "examples": [ - null - ], - "title": "Pvforecast2 Strings Per Inverter" - }, - "pvforecast2_surface_azimuth": { - "anyOf": [ - { - "type": "number" - }, - { - "type": "null" - } - ], - "description": "Orientation (azimuth angle) of the (fixed) plane. Clockwise from north (north=0, east=90, south=180, west=270).", - "examples": [ - null - ], - "title": "Pvforecast2 Surface Azimuth" - }, - "pvforecast2_surface_tilt": { - "anyOf": [ - { - "type": "number" - }, - { - "type": "null" - } - ], - "description": "Tilt angle from horizontal plane. Ignored for two-axis tracking.", - "examples": [ - null - ], - "title": "Pvforecast2 Surface Tilt" - }, - "pvforecast2_trackingtype": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "description": "Type of suntracking. 0=fixed, 1=single horizontal axis aligned north-south, 2=two-axis tracking, 3=vertical axis tracking, 4=single horizontal axis aligned east-west, 5=single inclined axis aligned north-south.", - "examples": [ - null - ], - "title": "Pvforecast2 Trackingtype" - }, - "pvforecast2_userhorizon": { - "anyOf": [ - { - "items": { - "type": "number" - }, - "type": "array" - }, - { - "type": "null" - } - ], - "description": "Elevation of horizon in degrees, at equally spaced azimuth clockwise from north.", - "examples": [ - null - ], - "title": "Pvforecast2 Userhorizon" - }, - "pvforecast3_albedo": { - "anyOf": [ - { - "type": "number" - }, - { - "type": "null" - } - ], - "description": "Proportion of the light hitting the ground that it reflects back.", - "examples": [ - null - ], - "title": "Pvforecast3 Albedo" - }, - "pvforecast3_inverter_model": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "description": "Model of the inverter of this plane.", - "examples": [ - null - ], - "title": "Pvforecast3 Inverter Model" - }, - "pvforecast3_inverter_paco": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "description": "AC power rating of the inverter. [W]", - "examples": [ - null - ], - "title": "Pvforecast3 Inverter Paco" - }, - "pvforecast3_loss": { - "anyOf": [ - { - "type": "number" - }, - { - "type": "null" - } - ], - "default": 14.0, - "description": "Sum of PV system losses in percent", - "examples": [ - null - ], - "title": "Pvforecast3 Loss" - }, - "pvforecast3_module_model": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "description": "Model of the PV modules of this plane.", - "examples": [ - null - ], - "title": "Pvforecast3 Module Model" - }, - "pvforecast3_modules_per_string": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "description": "Number of the PV modules of the strings of this plane.", - "examples": [ - null - ], - "title": "Pvforecast3 Modules Per String" - }, - "pvforecast3_mountingplace": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "default": "free", - "description": "Type of mounting for PV system. Options are 'free' for free-standing and 'building' for building-integrated.", - "examples": [ - null - ], - "title": "Pvforecast3 Mountingplace" - }, - "pvforecast3_optimal_surface_tilt": { - "anyOf": [ - { - "type": "boolean" - }, - { - "type": "null" - } - ], - "default": false, - "description": "Calculate the optimum tilt angle. Ignored for two-axis tracking.", - "examples": [ - null - ], - "title": "Pvforecast3 Optimal Surface Tilt" - }, - "pvforecast3_optimalangles": { - "anyOf": [ - { - "type": "boolean" - }, - { - "type": "null" - } - ], - "default": false, - "description": "Calculate the optimum tilt and azimuth angles. Ignored for two-axis tracking.", - "examples": [ - null - ], - "title": "Pvforecast3 Optimalangles" - }, - "pvforecast3_peakpower": { - "anyOf": [ - { - "type": "number" - }, - { - "type": "null" - } - ], - "description": "Nominal power of PV system in kW.", - "examples": [ - null - ], - "title": "Pvforecast3 Peakpower" - }, - "pvforecast3_pvtechchoice": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "default": "crystSi", - "description": "PV technology. One of 'crystSi', 'CIS', 'CdTe', 'Unknown'.", - "examples": [ - null - ], - "title": "Pvforecast3 Pvtechchoice" - }, - "pvforecast3_strings_per_inverter": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "description": "Number of the strings of the inverter of this plane.", - "examples": [ - null - ], - "title": "Pvforecast3 Strings Per Inverter" - }, - "pvforecast3_surface_azimuth": { - "anyOf": [ - { - "type": "number" - }, - { - "type": "null" - } - ], - "description": "Orientation (azimuth angle) of the (fixed) plane. Clockwise from north (north=0, east=90, south=180, west=270).", - "examples": [ - null - ], - "title": "Pvforecast3 Surface Azimuth" - }, - "pvforecast3_surface_tilt": { - "anyOf": [ - { - "type": "number" - }, - { - "type": "null" - } - ], - "description": "Tilt angle from horizontal plane. Ignored for two-axis tracking.", - "examples": [ - null - ], - "title": "Pvforecast3 Surface Tilt" - }, - "pvforecast3_trackingtype": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "description": "Type of suntracking. 0=fixed, 1=single horizontal axis aligned north-south, 2=two-axis tracking, 3=vertical axis tracking, 4=single horizontal axis aligned east-west, 5=single inclined axis aligned north-south.", - "examples": [ - null - ], - "title": "Pvforecast3 Trackingtype" - }, - "pvforecast3_userhorizon": { - "anyOf": [ - { - "items": { - "type": "number" - }, - "type": "array" - }, - { - "type": "null" - } - ], - "description": "Elevation of horizon in degrees, at equally spaced azimuth clockwise from north.", - "examples": [ - null - ], - "title": "Pvforecast3 Userhorizon" - }, - "pvforecast4_albedo": { - "anyOf": [ - { - "type": "number" - }, - { - "type": "null" - } - ], - "description": "Proportion of the light hitting the ground that it reflects back.", - "examples": [ - null - ], - "title": "Pvforecast4 Albedo" - }, - "pvforecast4_inverter_model": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "description": "Model of the inverter of this plane.", - "examples": [ - null - ], - "title": "Pvforecast4 Inverter Model" - }, - "pvforecast4_inverter_paco": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "description": "AC power rating of the inverter. [W]", - "examples": [ - null - ], - "title": "Pvforecast4 Inverter Paco" - }, - "pvforecast4_loss": { - "anyOf": [ - { - "type": "number" - }, - { - "type": "null" - } - ], - "default": 14.0, - "description": "Sum of PV system losses in percent", - "examples": [ - null - ], - "title": "Pvforecast4 Loss" - }, - "pvforecast4_module_model": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "description": "Model of the PV modules of this plane.", - "examples": [ - null - ], - "title": "Pvforecast4 Module Model" - }, - "pvforecast4_modules_per_string": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "description": "Number of the PV modules of the strings of this plane.", - "examples": [ - null - ], - "title": "Pvforecast4 Modules Per String" - }, - "pvforecast4_mountingplace": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "default": "free", - "description": "Type of mounting for PV system. Options are 'free' for free-standing and 'building' for building-integrated.", - "examples": [ - null - ], - "title": "Pvforecast4 Mountingplace" - }, - "pvforecast4_optimal_surface_tilt": { - "anyOf": [ - { - "type": "boolean" - }, - { - "type": "null" - } - ], - "default": false, - "description": "Calculate the optimum tilt angle. Ignored for two-axis tracking.", - "examples": [ - null - ], - "title": "Pvforecast4 Optimal Surface Tilt" - }, - "pvforecast4_optimalangles": { - "anyOf": [ - { - "type": "boolean" - }, - { - "type": "null" - } - ], - "default": false, - "description": "Calculate the optimum tilt and azimuth angles. Ignored for two-axis tracking.", - "examples": [ - null - ], - "title": "Pvforecast4 Optimalangles" - }, - "pvforecast4_peakpower": { - "anyOf": [ - { - "type": "number" - }, - { - "type": "null" - } - ], - "description": "Nominal power of PV system in kW.", - "examples": [ - null - ], - "title": "Pvforecast4 Peakpower" - }, - "pvforecast4_pvtechchoice": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "default": "crystSi", - "description": "PV technology. One of 'crystSi', 'CIS', 'CdTe', 'Unknown'.", - "examples": [ - null - ], - "title": "Pvforecast4 Pvtechchoice" - }, - "pvforecast4_strings_per_inverter": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "description": "Number of the strings of the inverter of this plane.", - "examples": [ - null - ], - "title": "Pvforecast4 Strings Per Inverter" - }, - "pvforecast4_surface_azimuth": { - "anyOf": [ - { - "type": "number" - }, - { - "type": "null" - } - ], - "description": "Orientation (azimuth angle) of the (fixed) plane. Clockwise from north (north=0, east=90, south=180, west=270).", - "examples": [ - null - ], - "title": "Pvforecast4 Surface Azimuth" - }, - "pvforecast4_surface_tilt": { - "anyOf": [ - { - "type": "number" - }, - { - "type": "null" - } - ], - "description": "Tilt angle from horizontal plane. Ignored for two-axis tracking.", - "examples": [ - null - ], - "title": "Pvforecast4 Surface Tilt" - }, - "pvforecast4_trackingtype": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "description": "Type of suntracking. 0=fixed, 1=single horizontal axis aligned north-south, 2=two-axis tracking, 3=vertical axis tracking, 4=single horizontal axis aligned east-west, 5=single inclined axis aligned north-south.", - "examples": [ - null - ], - "title": "Pvforecast4 Trackingtype" - }, - "pvforecast4_userhorizon": { - "anyOf": [ - { - "items": { - "type": "number" - }, - "type": "array" - }, - { - "type": "null" - } - ], - "description": "Elevation of horizon in degrees, at equally spaced azimuth clockwise from north.", - "examples": [ - null - ], - "title": "Pvforecast4 Userhorizon" - }, - "pvforecast5_albedo": { - "anyOf": [ - { - "type": "number" - }, - { - "type": "null" - } - ], - "description": "Proportion of the light hitting the ground that it reflects back.", - "examples": [ - null - ], - "title": "Pvforecast5 Albedo" - }, - "pvforecast5_inverter_model": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "description": "Model of the inverter of this plane.", - "examples": [ - null - ], - "title": "Pvforecast5 Inverter Model" - }, - "pvforecast5_inverter_paco": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "description": "AC power rating of the inverter. [W]", - "examples": [ - null - ], - "title": "Pvforecast5 Inverter Paco" - }, - "pvforecast5_loss": { - "anyOf": [ - { - "type": "number" - }, - { - "type": "null" - } - ], - "default": 14.0, - "description": "Sum of PV system losses in percent", - "examples": [ - null - ], - "title": "Pvforecast5 Loss" - }, - "pvforecast5_module_model": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "description": "Model of the PV modules of this plane.", - "examples": [ - null - ], - "title": "Pvforecast5 Module Model" - }, - "pvforecast5_modules_per_string": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "description": "Number of the PV modules of the strings of this plane.", - "examples": [ - null - ], - "title": "Pvforecast5 Modules Per String" - }, - "pvforecast5_mountingplace": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "default": "free", - "description": "Type of mounting for PV system. Options are 'free' for free-standing and 'building' for building-integrated.", - "examples": [ - null - ], - "title": "Pvforecast5 Mountingplace" - }, - "pvforecast5_optimal_surface_tilt": { - "anyOf": [ - { - "type": "boolean" - }, - { - "type": "null" - } - ], - "default": false, - "description": "Calculate the optimum tilt angle. Ignored for two-axis tracking.", - "examples": [ - null - ], - "title": "Pvforecast5 Optimal Surface Tilt" - }, - "pvforecast5_optimalangles": { - "anyOf": [ - { - "type": "boolean" - }, - { - "type": "null" - } - ], - "default": false, - "description": "Calculate the optimum tilt and azimuth angles. Ignored for two-axis tracking.", - "examples": [ - null - ], - "title": "Pvforecast5 Optimalangles" - }, - "pvforecast5_peakpower": { - "anyOf": [ - { - "type": "number" - }, - { - "type": "null" - } - ], - "description": "Nominal power of PV system in kW.", - "examples": [ - null - ], - "title": "Pvforecast5 Peakpower" - }, - "pvforecast5_pvtechchoice": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "default": "crystSi", - "description": "PV technology. One of 'crystSi', 'CIS', 'CdTe', 'Unknown'.", - "examples": [ - null - ], - "title": "Pvforecast5 Pvtechchoice" - }, - "pvforecast5_strings_per_inverter": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "description": "Number of the strings of the inverter of this plane.", - "examples": [ - null - ], - "title": "Pvforecast5 Strings Per Inverter" - }, - "pvforecast5_surface_azimuth": { - "anyOf": [ - { - "type": "number" - }, - { - "type": "null" - } - ], - "description": "Orientation (azimuth angle) of the (fixed) plane. Clockwise from north (north=0, east=90, south=180, west=270).", - "examples": [ - null - ], - "title": "Pvforecast5 Surface Azimuth" - }, - "pvforecast5_surface_tilt": { - "anyOf": [ - { - "type": "number" - }, - { - "type": "null" - } - ], - "description": "Tilt angle from horizontal plane. Ignored for two-axis tracking.", - "examples": [ - null - ], - "title": "Pvforecast5 Surface Tilt" - }, - "pvforecast5_trackingtype": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "description": "Type of suntracking. 0=fixed, 1=single horizontal axis aligned north-south, 2=two-axis tracking, 3=vertical axis tracking, 4=single horizontal axis aligned east-west, 5=single inclined axis aligned north-south.", - "examples": [ - null - ], - "title": "Pvforecast5 Trackingtype" - }, - "pvforecast5_userhorizon": { - "anyOf": [ - { - "items": { - "type": "number" - }, - "type": "array" - }, - { - "type": "null" - } - ], - "description": "Elevation of horizon in degrees, at equally spaced azimuth clockwise from north.", - "examples": [ - null - ], - "title": "Pvforecast5 Userhorizon" } }, "title": "PVForecastCommonSettings", @@ -2972,6 +1515,100 @@ "PVForecastCommonSettings-Output": { "description": "PV Forecast Configuration.", "properties": { + "planes": { + "anyOf": [ + { + "items": { + "$ref": "#/components/schemas/PVForecastPlaneSetting" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "description": "Plane configuration.", + "examples": [ + [ + { + "inverter_paco": 6000, + "loss": 14.0, + "modules_per_string": 20, + "mountingplace": "free", + "optimal_surface_tilt": false, + "optimalangles": false, + "peakpower": 5.0, + "pvtechchoice": "crystSi", + "strings_per_inverter": 2, + "surface_azimuth": 10.0, + "surface_tilt": 10.0, + "trackingtype": 0, + "userhorizon": [ + 10.0, + 20.0, + 30.0 + ] + }, + { + "inverter_paco": 4000, + "loss": 14.0, + "modules_per_string": 20, + "mountingplace": "free", + "optimal_surface_tilt": false, + "optimalangles": false, + "peakpower": 3.5, + "pvtechchoice": "crystSi", + "strings_per_inverter": 2, + "surface_azimuth": 20.0, + "surface_tilt": 20.0, + "trackingtype": 1, + "userhorizon": [ + 5.0, + 15.0, + 25.0 + ] + } + ] + ], + "title": "Planes" + }, + "planes_azimuth": { + "description": "Compute a list of the azimuths per active planes.", + "items": { + "type": "number" + }, + "readOnly": true, + "title": "Planes Azimuth", + "type": "array" + }, + "planes_inverter_paco": { + "description": "Compute a list of the maximum power rating of the inverter per active planes.", + "readOnly": true, + "title": "Planes Inverter Paco" + }, + "planes_peakpower": { + "description": "Compute a list of the peak power per active planes.", + "items": { + "type": "number" + }, + "readOnly": true, + "title": "Planes Peakpower", + "type": "array" + }, + "planes_tilt": { + "description": "Compute a list of the tilts per active planes.", + "items": { + "type": "number" + }, + "readOnly": true, + "title": "Planes Tilt", + "type": "array" + }, + "planes_userhorizon": { + "description": "Compute a list of the user horizon per active planes.", + "readOnly": true, + "title": "Planes Userhorizon" + }, "provider": { "anyOf": [ { @@ -3000,1544 +1637,14 @@ "examples": [ null ] - }, - "pvforecast0_albedo": { - "anyOf": [ - { - "type": "number" - }, - { - "type": "null" - } - ], - "description": "Proportion of the light hitting the ground that it reflects back.", - "examples": [ - null - ], - "title": "Pvforecast0 Albedo" - }, - "pvforecast0_inverter_model": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "description": "Model of the inverter of this plane.", - "examples": [ - null - ], - "title": "Pvforecast0 Inverter Model" - }, - "pvforecast0_inverter_paco": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "description": "AC power rating of the inverter. [W]", - "examples": [ - 6000 - ], - "title": "Pvforecast0 Inverter Paco" - }, - "pvforecast0_loss": { - "anyOf": [ - { - "type": "number" - }, - { - "type": "null" - } - ], - "default": 14.0, - "description": "Sum of PV system losses in percent", - "title": "Pvforecast0 Loss" - }, - "pvforecast0_module_model": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "description": "Model of the PV modules of this plane.", - "examples": [ - null - ], - "title": "Pvforecast0 Module Model" - }, - "pvforecast0_modules_per_string": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "description": "Number of the PV modules of the strings of this plane.", - "examples": [ - 20 - ], - "title": "Pvforecast0 Modules Per String" - }, - "pvforecast0_mountingplace": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "default": "free", - "description": "Type of mounting for PV system. Options are 'free' for free-standing and 'building' for building-integrated.", - "title": "Pvforecast0 Mountingplace" - }, - "pvforecast0_optimal_surface_tilt": { - "anyOf": [ - { - "type": "boolean" - }, - { - "type": "null" - } - ], - "default": false, - "description": "Calculate the optimum tilt angle. Ignored for two-axis tracking.", - "examples": [ - false - ], - "title": "Pvforecast0 Optimal Surface Tilt" - }, - "pvforecast0_optimalangles": { - "anyOf": [ - { - "type": "boolean" - }, - { - "type": "null" - } - ], - "default": false, - "description": "Calculate the optimum tilt and azimuth angles. Ignored for two-axis tracking.", - "examples": [ - false - ], - "title": "Pvforecast0 Optimalangles" - }, - "pvforecast0_peakpower": { - "anyOf": [ - { - "type": "number" - }, - { - "type": "null" - } - ], - "description": "Nominal power of PV system in kW.", - "examples": [ - 5.0 - ], - "title": "Pvforecast0 Peakpower" - }, - "pvforecast0_pvtechchoice": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "default": "crystSi", - "description": "PV technology. One of 'crystSi', 'CIS', 'CdTe', 'Unknown'.", - "title": "Pvforecast0 Pvtechchoice" - }, - "pvforecast0_strings_per_inverter": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "description": "Number of the strings of the inverter of this plane.", - "examples": [ - 2 - ], - "title": "Pvforecast0 Strings Per Inverter" - }, - "pvforecast0_surface_azimuth": { - "anyOf": [ - { - "type": "number" - }, - { - "type": "null" - } - ], - "description": "Orientation (azimuth angle) of the (fixed) plane. Clockwise from north (north=0, east=90, south=180, west=270).", - "examples": [ - 10.0 - ], - "title": "Pvforecast0 Surface Azimuth" - }, - "pvforecast0_surface_tilt": { - "anyOf": [ - { - "type": "number" - }, - { - "type": "null" - } - ], - "description": "Tilt angle from horizontal plane. Ignored for two-axis tracking.", - "examples": [ - 10.0 - ], - "title": "Pvforecast0 Surface Tilt" - }, - "pvforecast0_trackingtype": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "description": "Type of suntracking. 0=fixed, 1=single horizontal axis aligned north-south, 2=two-axis tracking, 3=vertical axis tracking, 4=single horizontal axis aligned east-west, 5=single inclined axis aligned north-south.", - "examples": [ - 0, - 1, - 2, - 3, - 4, - 5 - ], - "title": "Pvforecast0 Trackingtype" - }, - "pvforecast0_userhorizon": { - "anyOf": [ - { - "items": { - "type": "number" - }, - "type": "array" - }, - { - "type": "null" - } - ], - "description": "Elevation of horizon in degrees, at equally spaced azimuth clockwise from north.", - "examples": [ - [ - 10.0, - 20.0, - 30.0 - ] - ], - "title": "Pvforecast0 Userhorizon" - }, - "pvforecast1_albedo": { - "anyOf": [ - { - "type": "number" - }, - { - "type": "null" - } - ], - "description": "Proportion of the light hitting the ground that it reflects back.", - "examples": [ - null - ], - "title": "Pvforecast1 Albedo" - }, - "pvforecast1_inverter_model": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "description": "Model of the inverter of this plane.", - "examples": [ - null - ], - "title": "Pvforecast1 Inverter Model" - }, - "pvforecast1_inverter_paco": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "description": "AC power rating of the inverter. [W]", - "examples": [ - 4000 - ], - "title": "Pvforecast1 Inverter Paco" - }, - "pvforecast1_loss": { - "anyOf": [ - { - "type": "number" - }, - { - "type": "null" - } - ], - "default": 14.0, - "description": "Sum of PV system losses in percent", - "title": "Pvforecast1 Loss" - }, - "pvforecast1_module_model": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "description": "Model of the PV modules of this plane.", - "examples": [ - null - ], - "title": "Pvforecast1 Module Model" - }, - "pvforecast1_modules_per_string": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "description": "Number of the PV modules of the strings of this plane.", - "examples": [ - 20 - ], - "title": "Pvforecast1 Modules Per String" - }, - "pvforecast1_mountingplace": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "default": "free", - "description": "Type of mounting for PV system. Options are 'free' for free-standing and 'building' for building-integrated.", - "title": "Pvforecast1 Mountingplace" - }, - "pvforecast1_optimal_surface_tilt": { - "anyOf": [ - { - "type": "boolean" - }, - { - "type": "null" - } - ], - "default": false, - "description": "Calculate the optimum tilt angle. Ignored for two-axis tracking.", - "examples": [ - false - ], - "title": "Pvforecast1 Optimal Surface Tilt" - }, - "pvforecast1_optimalangles": { - "anyOf": [ - { - "type": "boolean" - }, - { - "type": "null" - } - ], - "default": false, - "description": "Calculate the optimum tilt and azimuth angles. Ignored for two-axis tracking.", - "examples": [ - false - ], - "title": "Pvforecast1 Optimalangles" - }, - "pvforecast1_peakpower": { - "anyOf": [ - { - "type": "number" - }, - { - "type": "null" - } - ], - "description": "Nominal power of PV system in kW.", - "examples": [ - 3.5 - ], - "title": "Pvforecast1 Peakpower" - }, - "pvforecast1_pvtechchoice": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "default": "crystSi", - "description": "PV technology. One of 'crystSi', 'CIS', 'CdTe', 'Unknown'.", - "title": "Pvforecast1 Pvtechchoice" - }, - "pvforecast1_strings_per_inverter": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "description": "Number of the strings of the inverter of this plane.", - "examples": [ - 2 - ], - "title": "Pvforecast1 Strings Per Inverter" - }, - "pvforecast1_surface_azimuth": { - "anyOf": [ - { - "type": "number" - }, - { - "type": "null" - } - ], - "description": "Orientation (azimuth angle) of the (fixed) plane. Clockwise from north (north=0, east=90, south=180, west=270).", - "examples": [ - 20.0 - ], - "title": "Pvforecast1 Surface Azimuth" - }, - "pvforecast1_surface_tilt": { - "anyOf": [ - { - "type": "number" - }, - { - "type": "null" - } - ], - "description": "Tilt angle from horizontal plane. Ignored for two-axis tracking.", - "examples": [ - 20.0 - ], - "title": "Pvforecast1 Surface Tilt" - }, - "pvforecast1_trackingtype": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "description": "Type of suntracking. 0=fixed, 1=single horizontal axis aligned north-south, 2=two-axis tracking, 3=vertical axis tracking, 4=single horizontal axis aligned east-west, 5=single inclined axis aligned north-south.", - "examples": [ - null - ], - "title": "Pvforecast1 Trackingtype" - }, - "pvforecast1_userhorizon": { - "anyOf": [ - { - "items": { - "type": "number" - }, - "type": "array" - }, - { - "type": "null" - } - ], - "description": "Elevation of horizon in degrees, at equally spaced azimuth clockwise from north.", - "examples": [ - [ - 5.0, - 15.0, - 25.0 - ] - ], - "title": "Pvforecast1 Userhorizon" - }, - "pvforecast2_albedo": { - "anyOf": [ - { - "type": "number" - }, - { - "type": "null" - } - ], - "description": "Proportion of the light hitting the ground that it reflects back.", - "examples": [ - null - ], - "title": "Pvforecast2 Albedo" - }, - "pvforecast2_inverter_model": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "description": "Model of the inverter of this plane.", - "examples": [ - null - ], - "title": "Pvforecast2 Inverter Model" - }, - "pvforecast2_inverter_paco": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "description": "AC power rating of the inverter. [W]", - "examples": [ - null - ], - "title": "Pvforecast2 Inverter Paco" - }, - "pvforecast2_loss": { - "anyOf": [ - { - "type": "number" - }, - { - "type": "null" - } - ], - "default": 14.0, - "description": "Sum of PV system losses in percent", - "examples": [ - null - ], - "title": "Pvforecast2 Loss" - }, - "pvforecast2_module_model": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "description": "Model of the PV modules of this plane.", - "examples": [ - null - ], - "title": "Pvforecast2 Module Model" - }, - "pvforecast2_modules_per_string": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "description": "Number of the PV modules of the strings of this plane.", - "examples": [ - null - ], - "title": "Pvforecast2 Modules Per String" - }, - "pvforecast2_mountingplace": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "default": "free", - "description": "Type of mounting for PV system. Options are 'free' for free-standing and 'building' for building-integrated.", - "examples": [ - null - ], - "title": "Pvforecast2 Mountingplace" - }, - "pvforecast2_optimal_surface_tilt": { - "anyOf": [ - { - "type": "boolean" - }, - { - "type": "null" - } - ], - "default": false, - "description": "Calculate the optimum tilt angle. Ignored for two-axis tracking.", - "examples": [ - null - ], - "title": "Pvforecast2 Optimal Surface Tilt" - }, - "pvforecast2_optimalangles": { - "anyOf": [ - { - "type": "boolean" - }, - { - "type": "null" - } - ], - "default": false, - "description": "Calculate the optimum tilt and azimuth angles. Ignored for two-axis tracking.", - "examples": [ - null - ], - "title": "Pvforecast2 Optimalangles" - }, - "pvforecast2_peakpower": { - "anyOf": [ - { - "type": "number" - }, - { - "type": "null" - } - ], - "description": "Nominal power of PV system in kW.", - "examples": [ - null - ], - "title": "Pvforecast2 Peakpower" - }, - "pvforecast2_pvtechchoice": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "default": "crystSi", - "description": "PV technology. One of 'crystSi', 'CIS', 'CdTe', 'Unknown'.", - "examples": [ - null - ], - "title": "Pvforecast2 Pvtechchoice" - }, - "pvforecast2_strings_per_inverter": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "description": "Number of the strings of the inverter of this plane.", - "examples": [ - null - ], - "title": "Pvforecast2 Strings Per Inverter" - }, - "pvforecast2_surface_azimuth": { - "anyOf": [ - { - "type": "number" - }, - { - "type": "null" - } - ], - "description": "Orientation (azimuth angle) of the (fixed) plane. Clockwise from north (north=0, east=90, south=180, west=270).", - "examples": [ - null - ], - "title": "Pvforecast2 Surface Azimuth" - }, - "pvforecast2_surface_tilt": { - "anyOf": [ - { - "type": "number" - }, - { - "type": "null" - } - ], - "description": "Tilt angle from horizontal plane. Ignored for two-axis tracking.", - "examples": [ - null - ], - "title": "Pvforecast2 Surface Tilt" - }, - "pvforecast2_trackingtype": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "description": "Type of suntracking. 0=fixed, 1=single horizontal axis aligned north-south, 2=two-axis tracking, 3=vertical axis tracking, 4=single horizontal axis aligned east-west, 5=single inclined axis aligned north-south.", - "examples": [ - null - ], - "title": "Pvforecast2 Trackingtype" - }, - "pvforecast2_userhorizon": { - "anyOf": [ - { - "items": { - "type": "number" - }, - "type": "array" - }, - { - "type": "null" - } - ], - "description": "Elevation of horizon in degrees, at equally spaced azimuth clockwise from north.", - "examples": [ - null - ], - "title": "Pvforecast2 Userhorizon" - }, - "pvforecast3_albedo": { - "anyOf": [ - { - "type": "number" - }, - { - "type": "null" - } - ], - "description": "Proportion of the light hitting the ground that it reflects back.", - "examples": [ - null - ], - "title": "Pvforecast3 Albedo" - }, - "pvforecast3_inverter_model": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "description": "Model of the inverter of this plane.", - "examples": [ - null - ], - "title": "Pvforecast3 Inverter Model" - }, - "pvforecast3_inverter_paco": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "description": "AC power rating of the inverter. [W]", - "examples": [ - null - ], - "title": "Pvforecast3 Inverter Paco" - }, - "pvforecast3_loss": { - "anyOf": [ - { - "type": "number" - }, - { - "type": "null" - } - ], - "default": 14.0, - "description": "Sum of PV system losses in percent", - "examples": [ - null - ], - "title": "Pvforecast3 Loss" - }, - "pvforecast3_module_model": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "description": "Model of the PV modules of this plane.", - "examples": [ - null - ], - "title": "Pvforecast3 Module Model" - }, - "pvforecast3_modules_per_string": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "description": "Number of the PV modules of the strings of this plane.", - "examples": [ - null - ], - "title": "Pvforecast3 Modules Per String" - }, - "pvforecast3_mountingplace": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "default": "free", - "description": "Type of mounting for PV system. Options are 'free' for free-standing and 'building' for building-integrated.", - "examples": [ - null - ], - "title": "Pvforecast3 Mountingplace" - }, - "pvforecast3_optimal_surface_tilt": { - "anyOf": [ - { - "type": "boolean" - }, - { - "type": "null" - } - ], - "default": false, - "description": "Calculate the optimum tilt angle. Ignored for two-axis tracking.", - "examples": [ - null - ], - "title": "Pvforecast3 Optimal Surface Tilt" - }, - "pvforecast3_optimalangles": { - "anyOf": [ - { - "type": "boolean" - }, - { - "type": "null" - } - ], - "default": false, - "description": "Calculate the optimum tilt and azimuth angles. Ignored for two-axis tracking.", - "examples": [ - null - ], - "title": "Pvforecast3 Optimalangles" - }, - "pvforecast3_peakpower": { - "anyOf": [ - { - "type": "number" - }, - { - "type": "null" - } - ], - "description": "Nominal power of PV system in kW.", - "examples": [ - null - ], - "title": "Pvforecast3 Peakpower" - }, - "pvforecast3_pvtechchoice": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "default": "crystSi", - "description": "PV technology. One of 'crystSi', 'CIS', 'CdTe', 'Unknown'.", - "examples": [ - null - ], - "title": "Pvforecast3 Pvtechchoice" - }, - "pvforecast3_strings_per_inverter": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "description": "Number of the strings of the inverter of this plane.", - "examples": [ - null - ], - "title": "Pvforecast3 Strings Per Inverter" - }, - "pvforecast3_surface_azimuth": { - "anyOf": [ - { - "type": "number" - }, - { - "type": "null" - } - ], - "description": "Orientation (azimuth angle) of the (fixed) plane. Clockwise from north (north=0, east=90, south=180, west=270).", - "examples": [ - null - ], - "title": "Pvforecast3 Surface Azimuth" - }, - "pvforecast3_surface_tilt": { - "anyOf": [ - { - "type": "number" - }, - { - "type": "null" - } - ], - "description": "Tilt angle from horizontal plane. Ignored for two-axis tracking.", - "examples": [ - null - ], - "title": "Pvforecast3 Surface Tilt" - }, - "pvforecast3_trackingtype": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "description": "Type of suntracking. 0=fixed, 1=single horizontal axis aligned north-south, 2=two-axis tracking, 3=vertical axis tracking, 4=single horizontal axis aligned east-west, 5=single inclined axis aligned north-south.", - "examples": [ - null - ], - "title": "Pvforecast3 Trackingtype" - }, - "pvforecast3_userhorizon": { - "anyOf": [ - { - "items": { - "type": "number" - }, - "type": "array" - }, - { - "type": "null" - } - ], - "description": "Elevation of horizon in degrees, at equally spaced azimuth clockwise from north.", - "examples": [ - null - ], - "title": "Pvforecast3 Userhorizon" - }, - "pvforecast4_albedo": { - "anyOf": [ - { - "type": "number" - }, - { - "type": "null" - } - ], - "description": "Proportion of the light hitting the ground that it reflects back.", - "examples": [ - null - ], - "title": "Pvforecast4 Albedo" - }, - "pvforecast4_inverter_model": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "description": "Model of the inverter of this plane.", - "examples": [ - null - ], - "title": "Pvforecast4 Inverter Model" - }, - "pvforecast4_inverter_paco": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "description": "AC power rating of the inverter. [W]", - "examples": [ - null - ], - "title": "Pvforecast4 Inverter Paco" - }, - "pvforecast4_loss": { - "anyOf": [ - { - "type": "number" - }, - { - "type": "null" - } - ], - "default": 14.0, - "description": "Sum of PV system losses in percent", - "examples": [ - null - ], - "title": "Pvforecast4 Loss" - }, - "pvforecast4_module_model": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "description": "Model of the PV modules of this plane.", - "examples": [ - null - ], - "title": "Pvforecast4 Module Model" - }, - "pvforecast4_modules_per_string": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "description": "Number of the PV modules of the strings of this plane.", - "examples": [ - null - ], - "title": "Pvforecast4 Modules Per String" - }, - "pvforecast4_mountingplace": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "default": "free", - "description": "Type of mounting for PV system. Options are 'free' for free-standing and 'building' for building-integrated.", - "examples": [ - null - ], - "title": "Pvforecast4 Mountingplace" - }, - "pvforecast4_optimal_surface_tilt": { - "anyOf": [ - { - "type": "boolean" - }, - { - "type": "null" - } - ], - "default": false, - "description": "Calculate the optimum tilt angle. Ignored for two-axis tracking.", - "examples": [ - null - ], - "title": "Pvforecast4 Optimal Surface Tilt" - }, - "pvforecast4_optimalangles": { - "anyOf": [ - { - "type": "boolean" - }, - { - "type": "null" - } - ], - "default": false, - "description": "Calculate the optimum tilt and azimuth angles. Ignored for two-axis tracking.", - "examples": [ - null - ], - "title": "Pvforecast4 Optimalangles" - }, - "pvforecast4_peakpower": { - "anyOf": [ - { - "type": "number" - }, - { - "type": "null" - } - ], - "description": "Nominal power of PV system in kW.", - "examples": [ - null - ], - "title": "Pvforecast4 Peakpower" - }, - "pvforecast4_pvtechchoice": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "default": "crystSi", - "description": "PV technology. One of 'crystSi', 'CIS', 'CdTe', 'Unknown'.", - "examples": [ - null - ], - "title": "Pvforecast4 Pvtechchoice" - }, - "pvforecast4_strings_per_inverter": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "description": "Number of the strings of the inverter of this plane.", - "examples": [ - null - ], - "title": "Pvforecast4 Strings Per Inverter" - }, - "pvforecast4_surface_azimuth": { - "anyOf": [ - { - "type": "number" - }, - { - "type": "null" - } - ], - "description": "Orientation (azimuth angle) of the (fixed) plane. Clockwise from north (north=0, east=90, south=180, west=270).", - "examples": [ - null - ], - "title": "Pvforecast4 Surface Azimuth" - }, - "pvforecast4_surface_tilt": { - "anyOf": [ - { - "type": "number" - }, - { - "type": "null" - } - ], - "description": "Tilt angle from horizontal plane. Ignored for two-axis tracking.", - "examples": [ - null - ], - "title": "Pvforecast4 Surface Tilt" - }, - "pvforecast4_trackingtype": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "description": "Type of suntracking. 0=fixed, 1=single horizontal axis aligned north-south, 2=two-axis tracking, 3=vertical axis tracking, 4=single horizontal axis aligned east-west, 5=single inclined axis aligned north-south.", - "examples": [ - null - ], - "title": "Pvforecast4 Trackingtype" - }, - "pvforecast4_userhorizon": { - "anyOf": [ - { - "items": { - "type": "number" - }, - "type": "array" - }, - { - "type": "null" - } - ], - "description": "Elevation of horizon in degrees, at equally spaced azimuth clockwise from north.", - "examples": [ - null - ], - "title": "Pvforecast4 Userhorizon" - }, - "pvforecast5_albedo": { - "anyOf": [ - { - "type": "number" - }, - { - "type": "null" - } - ], - "description": "Proportion of the light hitting the ground that it reflects back.", - "examples": [ - null - ], - "title": "Pvforecast5 Albedo" - }, - "pvforecast5_inverter_model": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "description": "Model of the inverter of this plane.", - "examples": [ - null - ], - "title": "Pvforecast5 Inverter Model" - }, - "pvforecast5_inverter_paco": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "description": "AC power rating of the inverter. [W]", - "examples": [ - null - ], - "title": "Pvforecast5 Inverter Paco" - }, - "pvforecast5_loss": { - "anyOf": [ - { - "type": "number" - }, - { - "type": "null" - } - ], - "default": 14.0, - "description": "Sum of PV system losses in percent", - "examples": [ - null - ], - "title": "Pvforecast5 Loss" - }, - "pvforecast5_module_model": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "description": "Model of the PV modules of this plane.", - "examples": [ - null - ], - "title": "Pvforecast5 Module Model" - }, - "pvforecast5_modules_per_string": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "description": "Number of the PV modules of the strings of this plane.", - "examples": [ - null - ], - "title": "Pvforecast5 Modules Per String" - }, - "pvforecast5_mountingplace": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "default": "free", - "description": "Type of mounting for PV system. Options are 'free' for free-standing and 'building' for building-integrated.", - "examples": [ - null - ], - "title": "Pvforecast5 Mountingplace" - }, - "pvforecast5_optimal_surface_tilt": { - "anyOf": [ - { - "type": "boolean" - }, - { - "type": "null" - } - ], - "default": false, - "description": "Calculate the optimum tilt angle. Ignored for two-axis tracking.", - "examples": [ - null - ], - "title": "Pvforecast5 Optimal Surface Tilt" - }, - "pvforecast5_optimalangles": { - "anyOf": [ - { - "type": "boolean" - }, - { - "type": "null" - } - ], - "default": false, - "description": "Calculate the optimum tilt and azimuth angles. Ignored for two-axis tracking.", - "examples": [ - null - ], - "title": "Pvforecast5 Optimalangles" - }, - "pvforecast5_peakpower": { - "anyOf": [ - { - "type": "number" - }, - { - "type": "null" - } - ], - "description": "Nominal power of PV system in kW.", - "examples": [ - null - ], - "title": "Pvforecast5 Peakpower" - }, - "pvforecast5_pvtechchoice": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "default": "crystSi", - "description": "PV technology. One of 'crystSi', 'CIS', 'CdTe', 'Unknown'.", - "examples": [ - null - ], - "title": "Pvforecast5 Pvtechchoice" - }, - "pvforecast5_strings_per_inverter": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "description": "Number of the strings of the inverter of this plane.", - "examples": [ - null - ], - "title": "Pvforecast5 Strings Per Inverter" - }, - "pvforecast5_surface_azimuth": { - "anyOf": [ - { - "type": "number" - }, - { - "type": "null" - } - ], - "description": "Orientation (azimuth angle) of the (fixed) plane. Clockwise from north (north=0, east=90, south=180, west=270).", - "examples": [ - null - ], - "title": "Pvforecast5 Surface Azimuth" - }, - "pvforecast5_surface_tilt": { - "anyOf": [ - { - "type": "number" - }, - { - "type": "null" - } - ], - "description": "Tilt angle from horizontal plane. Ignored for two-axis tracking.", - "examples": [ - null - ], - "title": "Pvforecast5 Surface Tilt" - }, - "pvforecast5_trackingtype": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "description": "Type of suntracking. 0=fixed, 1=single horizontal axis aligned north-south, 2=two-axis tracking, 3=vertical axis tracking, 4=single horizontal axis aligned east-west, 5=single inclined axis aligned north-south.", - "examples": [ - null - ], - "title": "Pvforecast5 Trackingtype" - }, - "pvforecast5_userhorizon": { - "anyOf": [ - { - "items": { - "type": "number" - }, - "type": "array" - }, - { - "type": "null" - } - ], - "description": "Elevation of horizon in degrees, at equally spaced azimuth clockwise from north.", - "examples": [ - null - ], - "title": "Pvforecast5 Userhorizon" - }, - "pvforecast_planes": { - "description": "Compute a list of active planes.", - "items": { - "type": "string" - }, - "readOnly": true, - "title": "Pvforecast Planes", - "type": "array" - }, - "pvforecast_planes_azimuth": { - "description": "Compute a list of the azimuths per active planes.", - "items": { - "type": "number" - }, - "readOnly": true, - "title": "Pvforecast Planes Azimuth", - "type": "array" - }, - "pvforecast_planes_inverter_paco": { - "description": "Compute a list of the maximum power rating of the inverter per active planes.", - "readOnly": true, - "title": "Pvforecast Planes Inverter Paco" - }, - "pvforecast_planes_peakpower": { - "description": "Compute a list of the peak power per active planes.", - "items": { - "type": "number" - }, - "readOnly": true, - "title": "Pvforecast Planes Peakpower", - "type": "array" - }, - "pvforecast_planes_tilt": { - "description": "Compute a list of the tilts per active planes.", - "items": { - "type": "number" - }, - "readOnly": true, - "title": "Pvforecast Planes Tilt", - "type": "array" - }, - "pvforecast_planes_userhorizon": { - "description": "Compute a list of the user horizon per active planes.", - "readOnly": true, - "title": "Pvforecast Planes Userhorizon" } }, "required": [ - "pvforecast_planes", - "pvforecast_planes_peakpower", - "pvforecast_planes_azimuth", - "pvforecast_planes_tilt", - "pvforecast_planes_userhorizon", - "pvforecast_planes_inverter_paco" + "planes_peakpower", + "planes_azimuth", + "planes_tilt", + "planes_userhorizon", + "planes_inverter_paco" ], "title": "PVForecastCommonSettings", "type": "object" @@ -4545,7 +1652,7 @@ "PVForecastImportCommonSettings": { "description": "Common settings for pvforecast data import from file or JSON string.", "properties": { - "pvforecastimport_file_path": { + "import_file_path": { "anyOf": [ { "type": "string" @@ -4563,9 +1670,9 @@ null, "/path/to/pvforecast.json" ], - "title": "Pvforecastimport File Path" + "title": "Import File Path" }, - "pvforecastimport_json": { + "import_json": { "anyOf": [ { "type": "string" @@ -4578,12 +1685,278 @@ "examples": [ "{\"pvforecast_ac_power\": [0, 8.05, 352.91]}" ], - "title": "Pvforecastimport Json" + "title": "Import Json" } }, "title": "PVForecastImportCommonSettings", "type": "object" }, + "PVForecastPlaneSetting": { + "description": "PV Forecast Plane Configuration.", + "properties": { + "albedo": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "description": "Proportion of the light hitting the ground that it reflects back.", + "examples": [ + null + ], + "title": "Albedo" + }, + "inverter_model": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Model of the inverter of this plane.", + "examples": [ + null + ], + "title": "Inverter Model" + }, + "inverter_paco": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "description": "AC power rating of the inverter. [W]", + "examples": [ + 6000, + 4000 + ], + "title": "Inverter Paco" + }, + "loss": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "default": 14.0, + "description": "Sum of PV system losses in percent", + "title": "Loss" + }, + "module_model": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Model of the PV modules of this plane.", + "examples": [ + null + ], + "title": "Module Model" + }, + "modules_per_string": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "description": "Number of the PV modules of the strings of this plane.", + "examples": [ + 20 + ], + "title": "Modules Per String" + }, + "mountingplace": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "free", + "description": "Type of mounting for PV system. Options are 'free' for free-standing and 'building' for building-integrated.", + "title": "Mountingplace" + }, + "optimal_surface_tilt": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": false, + "description": "Calculate the optimum tilt angle. Ignored for two-axis tracking.", + "examples": [ + false + ], + "title": "Optimal Surface Tilt" + }, + "optimalangles": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": false, + "description": "Calculate the optimum tilt and azimuth angles. Ignored for two-axis tracking.", + "examples": [ + false + ], + "title": "Optimalangles" + }, + "peakpower": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "description": "Nominal power of PV system in kW.", + "examples": [ + 5.0, + 3.5 + ], + "title": "Peakpower" + }, + "pvtechchoice": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "crystSi", + "description": "PV technology. One of 'crystSi', 'CIS', 'CdTe', 'Unknown'.", + "title": "Pvtechchoice" + }, + "strings_per_inverter": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "description": "Number of the strings of the inverter of this plane.", + "examples": [ + 2 + ], + "title": "Strings Per Inverter" + }, + "surface_azimuth": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "description": "Orientation (azimuth angle) of the (fixed) plane. Clockwise from north (north=0, east=90, south=180, west=270).", + "examples": [ + 10.0, + 20.0 + ], + "title": "Surface Azimuth" + }, + "surface_tilt": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "description": "Tilt angle from horizontal plane. Ignored for two-axis tracking.", + "examples": [ + 10.0, + 20.0 + ], + "title": "Surface Tilt" + }, + "trackingtype": { + "anyOf": [ + { + "maximum": 5.0, + "minimum": 0.0, + "type": "integer" + }, + { + "type": "null" + } + ], + "description": "Type of suntracking. 0=fixed, 1=single horizontal axis aligned north-south, 2=two-axis tracking, 3=vertical axis tracking, 4=single horizontal axis aligned east-west, 5=single inclined axis aligned north-south.", + "examples": [ + 0, + 1, + 2, + 3, + 4, + 5 + ], + "title": "Trackingtype" + }, + "userhorizon": { + "anyOf": [ + { + "items": { + "type": "number" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "description": "Elevation of horizon in degrees, at equally spaced azimuth clockwise from north.", + "examples": [ + [ + 10.0, + 20.0, + 30.0 + ], + [ + 5.0, + 15.0, + 25.0 + ] + ], + "title": "Userhorizon" + } + }, + "title": "PVForecastPlaneSetting", + "type": "object" + }, "PredictionCommonSettings-Input": { "description": "General Prediction Configuration.\n\nThis class provides configuration for prediction settings, allowing users to specify\nparameters such as the forecast duration (in hours) and location (latitude and longitude).\nValidators ensure each parameter is within a specified range. A computed property, `timezone`,\ndetermines the time zone based on latitude and longitude.\n\nAttributes:\n hours (Optional[int]): Number of hours into the future for predictions.\n Must be non-negative.\n historic_hours (Optional[int]): Number of hours into the past for historical data.\n Must be non-negative.\n latitude (Optional[float]): Latitude in degrees, must be between -90 and 90.\n longitude (Optional[float]): Longitude in degrees, must be between -180 and 180.\n\nProperties:\n timezone (Optional[str]): Computed time zone string based on the specified latitude\n and longitude.\n\nValidators:\n validate_hours (int): Ensures `hours` is a non-negative integer.\n validate_historic_hours (int): Ensures `historic_hours` is a non-negative integer.\n validate_latitude (float): Ensures `latitude` is within the range -90 to 90.\n validate_longitude (float): Ensures `longitude` is within the range -180 to 180.", "properties": { diff --git a/scripts/generate_config_md.py b/scripts/generate_config_md.py index e1bfe11..cbaefd0 100755 --- a/scripts/generate_config_md.py +++ b/scripts/generate_config_md.py @@ -13,6 +13,7 @@ from pydantic_core import PydanticUndefined from akkudoktoreos.config.config import get_config from akkudoktoreos.core.logging import get_logger from akkudoktoreos.core.pydantic import PydanticBaseModel +from akkudoktoreos.utils.docs import get_model_structure_from_examples logger = get_logger(__name__) @@ -51,23 +52,13 @@ def resolve_nested_types(field_type: Any, parent_types: list[str]) -> list[tuple return resolved_types -def get_example_or_default(field_name: str, field_info: FieldInfo) -> dict[str, Any]: - """Generate a default value for a field, considering constraints.""" - if field_info.examples is not None: - return field_info.examples[0] - - if field_info.default is not None: - return field_info.default - - raise NotImplementedError(f"No default or example provided '{field_name}': {field_info}") - - -def create_model_from_examples(model_class: PydanticBaseModel) -> PydanticBaseModel: +def create_model_from_examples( + model_class: PydanticBaseModel, multiple: bool +) -> list[PydanticBaseModel]: """Create a model instance with default or example values, respecting constraints.""" - example_data = {} - for field_name, field_info in model_class.model_fields.items(): - example_data[field_name] = get_example_or_default(field_name, field_info) - return model_class(**example_data) + return [ + model_class(**data) for data in get_model_structure_from_examples(model_class, multiple) + ] def build_nested_structure(keys: list[str], value: Any) -> Any: @@ -198,21 +189,29 @@ def generate_config_table_md( if toplevel: table += ":::\n\n" # Add an empty line after the table - ins = create_model_from_examples(config) - if ins: - # Transform to JSON (and manually to dict) to use custom serializers and then merge with parent keys - ins_json = ins.model_dump_json(include_computed_fields=False) - ins_dict = json.loads(ins_json) + has_examples_list = toplevel_keys[-1] == "list" + instance_list = create_model_from_examples(config, has_examples_list) + if instance_list: + ins_dict_list = [] + ins_out_dict_list = [] + for ins in instance_list: + # Transform to JSON (and manually to dict) to use custom serializers and then merge with parent keys + ins_json = ins.model_dump_json(include_computed_fields=False) + ins_dict_list.append(json.loads(ins_json)) - ins_out_json = ins.model_dump_json(include_computed_fields=True) - ins_out_dict = json.loads(ins_out_json) - same_output = ins_out_dict == ins_dict + ins_out_json = ins.model_dump_json(include_computed_fields=True) + ins_out_dict_list.append(json.loads(ins_out_json)) + + same_output = ins_out_dict_list == ins_dict_list same_output_str = "/Output" if same_output else "" table += f"#{heading_level} Example Input{same_output_str}\n\n" table += "```{eval-rst}\n" table += ".. code-block:: json\n\n" - input_dict = build_nested_structure(toplevel_keys, ins_dict) + if has_examples_list: + input_dict = build_nested_structure(toplevel_keys[:-1], ins_dict_list) + else: + input_dict = build_nested_structure(toplevel_keys, ins_dict_list[0]) table += textwrap.indent(json.dumps(input_dict, indent=4), " ") table += "\n" table += "```\n\n" @@ -221,7 +220,10 @@ def generate_config_table_md( table += f"#{heading_level} Example Output\n\n" table += "```{eval-rst}\n" table += ".. code-block:: json\n\n" - output_dict = build_nested_structure(toplevel_keys, ins_out_dict) + if has_examples_list: + output_dict = build_nested_structure(toplevel_keys[:-1], ins_out_dict_list) + else: + output_dict = build_nested_structure(toplevel_keys, ins_out_dict_list[0]) table += textwrap.indent(json.dumps(output_dict, indent=4), " ") table += "\n" table += "```\n\n" diff --git a/single_test_prediction.py b/single_test_prediction.py index aafe961..fc2e479 100644 --- a/single_test_prediction.py +++ b/single_test_prediction.py @@ -24,27 +24,36 @@ def config_pvforecast() -> dict: }, "pvforecast": { "provider": "PVForecastAkkudoktor", - "pvforecast0_peakpower": 5.0, - "pvforecast0_surface_azimuth": -10, - "pvforecast0_surface_tilt": 7, - "pvforecast0_userhorizon": [20, 27, 22, 20], - "pvforecast0_inverter_paco": 10000, - "pvforecast1_peakpower": 4.8, - "pvforecast1_surface_azimuth": -90, - "pvforecast1_surface_tilt": 7, - "pvforecast1_userhorizon": [30, 30, 30, 50], - "pvforecast1_inverter_paco": 10000, - "pvforecast2_peakpower": 1.4, - "pvforecast2_surface_azimuth": -40, - "pvforecast2_surface_tilt": 60, - "pvforecast2_userhorizon": [60, 30, 0, 30], - "pvforecast2_inverter_paco": 2000, - "pvforecast3_peakpower": 1.6, - "pvforecast3_surface_azimuth": 5, - "pvforecast3_surface_tilt": 45, - "pvforecast3_userhorizon": [45, 25, 30, 60], - "pvforecast3_inverter_paco": 1400, - "pvforecast4_peakpower": None, + "planes": [ + { + "peakpower": 5.0, + "surface_azimuth": -10, + "surface_tilt": 7, + "userhorizon": [20, 27, 22, 20], + "inverter_paco": 10000, + }, + { + "peakpower": 4.8, + "surface_azimuth": -90, + "surface_tilt": 7, + "userhorizon": [30, 30, 30, 50], + "inverter_paco": 10000, + }, + { + "peakpower": 1.4, + "surface_azimuth": -40, + "surface_tilt": 60, + "userhorizon": [60, 30, 0, 30], + "inverter_paco": 2000, + }, + { + "peakpower": 1.6, + "surface_azimuth": 5, + "surface_tilt": 45, + "userhorizon": [45, 25, 30, 60], + "inverter_paco": 1400, + }, + ], }, } return settings @@ -112,7 +121,7 @@ def run_prediction(provider_id: str, verbose: bool = False) -> str: elif provider_id in ("BrightSky", "ClearOutside"): settings = config_weather() settings["weather"]["provider"] = provider_id - elif provider_id in ("Akkudoktor",): + elif provider_id in ("ElecPriceAkkudoktor",): settings = config_elecprice() settings["elecprice"]["provider"] = provider_id elif provider_id in ("LoadAkkudoktor",): diff --git a/src/akkudoktoreos/prediction/pvforecast.py b/src/akkudoktoreos/prediction/pvforecast.py index 1d34e1f..bbfcc8e 100644 --- a/src/akkudoktoreos/prediction/pvforecast.py +++ b/src/akkudoktoreos/prediction/pvforecast.py @@ -1,16 +1,113 @@ """PV forecast module for PV power predictions.""" -from typing import Any, ClassVar, List, Optional +from typing import Any, ClassVar, List, Optional, Self -from pydantic import Field, computed_field +from pydantic import Field, computed_field, field_validator, model_validator from akkudoktoreos.config.configabc import SettingsBaseModel from akkudoktoreos.core.logging import get_logger from akkudoktoreos.prediction.pvforecastimport import PVForecastImportCommonSettings +from akkudoktoreos.utils.docs import get_model_structure_from_examples logger = get_logger(__name__) +class PVForecastPlaneSetting(SettingsBaseModel): + """PV Forecast Plane Configuration.""" + + # latitude: Optional[float] = Field(default=None, description="Latitude in decimal degrees, between -90 and 90, north is positive (ISO 19115) (°)") + surface_tilt: Optional[float] = Field( + default=None, + description="Tilt angle from horizontal plane. Ignored for two-axis tracking.", + examples=[10.0, 20.0], + ) + surface_azimuth: Optional[float] = Field( + default=None, + description="Orientation (azimuth angle) of the (fixed) plane. Clockwise from north (north=0, east=90, south=180, west=270).", + examples=[10.0, 20.0], + ) + userhorizon: Optional[List[float]] = Field( + default=None, + description="Elevation of horizon in degrees, at equally spaced azimuth clockwise from north.", + examples=[[10.0, 20.0, 30.0], [5.0, 15.0, 25.0]], + ) + peakpower: Optional[float] = Field( + default=None, description="Nominal power of PV system in kW.", examples=[5.0, 3.5] + ) + pvtechchoice: Optional[str] = Field( + default="crystSi", description="PV technology. One of 'crystSi', 'CIS', 'CdTe', 'Unknown'." + ) + mountingplace: Optional[str] = Field( + default="free", + description="Type of mounting for PV system. Options are 'free' for free-standing and 'building' for building-integrated.", + ) + loss: Optional[float] = Field(default=14.0, description="Sum of PV system losses in percent") + trackingtype: Optional[int] = Field( + default=None, + ge=0, + le=5, + description="Type of suntracking. 0=fixed, 1=single horizontal axis aligned north-south, 2=two-axis tracking, 3=vertical axis tracking, 4=single horizontal axis aligned east-west, 5=single inclined axis aligned north-south.", + examples=[0, 1, 2, 3, 4, 5], + ) + optimal_surface_tilt: Optional[bool] = Field( + default=False, + description="Calculate the optimum tilt angle. Ignored for two-axis tracking.", + examples=[False], + ) + optimalangles: Optional[bool] = Field( + default=False, + description="Calculate the optimum tilt and azimuth angles. Ignored for two-axis tracking.", + examples=[False], + ) + albedo: Optional[float] = Field( + default=None, + description="Proportion of the light hitting the ground that it reflects back.", + examples=[None], + ) + module_model: Optional[str] = Field( + default=None, description="Model of the PV modules of this plane.", examples=[None] + ) + inverter_model: Optional[str] = Field( + default=None, description="Model of the inverter of this plane.", examples=[None] + ) + inverter_paco: Optional[int] = Field( + default=None, description="AC power rating of the inverter. [W]", examples=[6000, 4000] + ) + modules_per_string: Optional[int] = Field( + default=None, + description="Number of the PV modules of the strings of this plane.", + examples=[20], + ) + strings_per_inverter: Optional[int] = Field( + default=None, + description="Number of the strings of the inverter of this plane.", + examples=[2], + ) + + @model_validator(mode="after") + def validate_list_length(self) -> Self: + # Check if either attribute is set and add to active planes + if self.trackingtype == 2: + # Tilt angle from horizontal plane is ignored for two-axis tracking. + if self.surface_azimuth is None: + raise ValueError("If trackingtype is set, azimuth must be set as well.") + elif self.surface_tilt is None or self.surface_azimuth is None: + raise ValueError("surface_tilt and surface_azimuth must be set.") + return self + + @field_validator("mountingplace") + def validate_mountingplace(cls, mountingplace: Optional[str]) -> Optional[str]: + if mountingplace is not None and mountingplace not in ["free", "building"]: + raise ValueError(f"Invalid mountingplace: {mountingplace}") + return mountingplace + + @field_validator("pvtechchoice") + def validate_pvtechchoice(cls, pvtechchoice: Optional[str]) -> Optional[str]: + if pvtechchoice is not None and pvtechchoice not in ["crystSi", "CIS", "CdTe", "Unknown"]: + raise ValueError(f"Invalid pvtechchoice: {pvtechchoice}") + return pvtechchoice + + class PVForecastCommonSettings(SettingsBaseModel): """PV Forecast Configuration.""" @@ -24,539 +121,109 @@ class PVForecastCommonSettings(SettingsBaseModel): description="PVForecast provider id of provider to be used.", examples=["PVForecastAkkudoktor"], ) - # pvforecast0_latitude: Optional[float] = Field(default=None, description="Latitude in decimal degrees, between -90 and 90, north is positive (ISO 19115) (°)") - # Plane 0 - pvforecast0_surface_tilt: Optional[float] = Field( + + planes: Optional[list[PVForecastPlaneSetting]] = Field( default=None, - description="Tilt angle from horizontal plane. Ignored for two-axis tracking.", - examples=[10.0], - ) - pvforecast0_surface_azimuth: Optional[float] = Field( - default=None, - description="Orientation (azimuth angle) of the (fixed) plane. Clockwise from north (north=0, east=90, south=180, west=270).", - examples=[10.0], - ) - pvforecast0_userhorizon: Optional[List[float]] = Field( - default=None, - description="Elevation of horizon in degrees, at equally spaced azimuth clockwise from north.", - examples=[[10.0, 20.0, 30.0]], - ) - pvforecast0_peakpower: Optional[float] = Field( - default=None, description="Nominal power of PV system in kW.", examples=[5.0] - ) - pvforecast0_pvtechchoice: Optional[str] = Field( - default="crystSi", description="PV technology. One of 'crystSi', 'CIS', 'CdTe', 'Unknown'." - ) - pvforecast0_mountingplace: Optional[str] = Field( - default="free", - description="Type of mounting for PV system. Options are 'free' for free-standing and 'building' for building-integrated.", - ) - pvforecast0_loss: Optional[float] = Field( - default=14.0, description="Sum of PV system losses in percent" - ) - pvforecast0_trackingtype: Optional[int] = Field( - default=None, - description="Type of suntracking. 0=fixed, 1=single horizontal axis aligned north-south, 2=two-axis tracking, 3=vertical axis tracking, 4=single horizontal axis aligned east-west, 5=single inclined axis aligned north-south.", - examples=[0, 1, 2, 3, 4, 5], - ) - pvforecast0_optimal_surface_tilt: Optional[bool] = Field( - default=False, - description="Calculate the optimum tilt angle. Ignored for two-axis tracking.", - examples=[False], - ) - pvforecast0_optimalangles: Optional[bool] = Field( - default=False, - description="Calculate the optimum tilt and azimuth angles. Ignored for two-axis tracking.", - examples=[False], - ) - pvforecast0_albedo: Optional[float] = Field( - default=None, - description="Proportion of the light hitting the ground that it reflects back.", - examples=[None], - ) - pvforecast0_module_model: Optional[str] = Field( - default=None, description="Model of the PV modules of this plane.", examples=[None] - ) - pvforecast0_inverter_model: Optional[str] = Field( - default=None, description="Model of the inverter of this plane.", examples=[None] - ) - pvforecast0_inverter_paco: Optional[int] = Field( - default=None, description="AC power rating of the inverter. [W]", examples=[6000] - ) - pvforecast0_modules_per_string: Optional[int] = Field( - default=None, - description="Number of the PV modules of the strings of this plane.", - examples=[20], - ) - pvforecast0_strings_per_inverter: Optional[int] = Field( - default=None, - description="Number of the strings of the inverter of this plane.", - examples=[2], - ) - # Plane 1 - pvforecast1_surface_tilt: Optional[float] = Field( - default=None, - description="Tilt angle from horizontal plane. Ignored for two-axis tracking.", - examples=[20.0], - ) - pvforecast1_surface_azimuth: Optional[float] = Field( - default=None, - description="Orientation (azimuth angle) of the (fixed) plane. Clockwise from north (north=0, east=90, south=180, west=270).", - examples=[20.0], - ) - pvforecast1_userhorizon: Optional[List[float]] = Field( - default=None, - description="Elevation of horizon in degrees, at equally spaced azimuth clockwise from north.", - examples=[[5.0, 15.0, 25.0]], - ) - pvforecast1_peakpower: Optional[float] = Field( - default=None, description="Nominal power of PV system in kW.", examples=[3.5] - ) - pvforecast1_pvtechchoice: Optional[str] = Field( - default="crystSi", description="PV technology. One of 'crystSi', 'CIS', 'CdTe', 'Unknown'." - ) - pvforecast1_mountingplace: Optional[str] = Field( - default="free", - description="Type of mounting for PV system. Options are 'free' for free-standing and 'building' for building-integrated.", - ) - pvforecast1_loss: Optional[float] = Field( - default=14.0, description="Sum of PV system losses in percent" - ) - pvforecast1_trackingtype: Optional[int] = Field( - default=None, - description="Type of suntracking. 0=fixed, 1=single horizontal axis aligned north-south, 2=two-axis tracking, 3=vertical axis tracking, 4=single horizontal axis aligned east-west, 5=single inclined axis aligned north-south.", - examples=[None], - ) - pvforecast1_optimal_surface_tilt: Optional[bool] = Field( - default=False, - description="Calculate the optimum tilt angle. Ignored for two-axis tracking.", - examples=[False], - ) - pvforecast1_optimalangles: Optional[bool] = Field( - default=False, - description="Calculate the optimum tilt and azimuth angles. Ignored for two-axis tracking.", - examples=[False], - ) - pvforecast1_albedo: Optional[float] = Field( - default=None, - description="Proportion of the light hitting the ground that it reflects back.", - examples=[None], - ) - pvforecast1_module_model: Optional[str] = Field( - default=None, description="Model of the PV modules of this plane.", examples=[None] - ) - pvforecast1_inverter_model: Optional[str] = Field( - default=None, description="Model of the inverter of this plane.", examples=[None] - ) - pvforecast1_inverter_paco: Optional[int] = Field( - default=None, description="AC power rating of the inverter. [W]", examples=[4000] - ) - pvforecast1_modules_per_string: Optional[int] = Field( - default=None, - description="Number of the PV modules of the strings of this plane.", - examples=[20], - ) - pvforecast1_strings_per_inverter: Optional[int] = Field( - default=None, - description="Number of the strings of the inverter of this plane.", - examples=[2], - ) - # Plane 2 - pvforecast2_surface_tilt: Optional[float] = Field( - default=None, - description="Tilt angle from horizontal plane. Ignored for two-axis tracking.", - examples=[None], - ) - pvforecast2_surface_azimuth: Optional[float] = Field( - default=None, - description="Orientation (azimuth angle) of the (fixed) plane. Clockwise from north (north=0, east=90, south=180, west=270).", - examples=[None], - ) - pvforecast2_userhorizon: Optional[List[float]] = Field( - default=None, - description="Elevation of horizon in degrees, at equally spaced azimuth clockwise from north.", - examples=[None], - ) - pvforecast2_peakpower: Optional[float] = Field( - default=None, description="Nominal power of PV system in kW.", examples=[None] - ) - pvforecast2_pvtechchoice: Optional[str] = Field( - default="crystSi", - description="PV technology. One of 'crystSi', 'CIS', 'CdTe', 'Unknown'.", - examples=[None], - ) - pvforecast2_mountingplace: Optional[str] = Field( - default="free", - description="Type of mounting for PV system. Options are 'free' for free-standing and 'building' for building-integrated.", - examples=[None], - ) - pvforecast2_loss: Optional[float] = Field( - default=14.0, description="Sum of PV system losses in percent", examples=[None] - ) - pvforecast2_trackingtype: Optional[int] = Field( - default=None, - description="Type of suntracking. 0=fixed, 1=single horizontal axis aligned north-south, 2=two-axis tracking, 3=vertical axis tracking, 4=single horizontal axis aligned east-west, 5=single inclined axis aligned north-south.", - examples=[None], - ) - pvforecast2_optimal_surface_tilt: Optional[bool] = Field( - default=False, - description="Calculate the optimum tilt angle. Ignored for two-axis tracking.", - examples=[None], - ) - pvforecast2_optimalangles: Optional[bool] = Field( - default=False, - description="Calculate the optimum tilt and azimuth angles. Ignored for two-axis tracking.", - examples=[None], - ) - pvforecast2_albedo: Optional[float] = Field( - default=None, - description="Proportion of the light hitting the ground that it reflects back.", - examples=[None], - ) - pvforecast2_module_model: Optional[str] = Field( - default=None, description="Model of the PV modules of this plane.", examples=[None] - ) - pvforecast2_inverter_model: Optional[str] = Field( - default=None, description="Model of the inverter of this plane.", examples=[None] - ) - pvforecast2_inverter_paco: Optional[int] = Field( - default=None, description="AC power rating of the inverter. [W]", examples=[None] - ) - pvforecast2_modules_per_string: Optional[int] = Field( - default=None, - description="Number of the PV modules of the strings of this plane.", - examples=[None], - ) - pvforecast2_strings_per_inverter: Optional[int] = Field( - default=None, - description="Number of the strings of the inverter of this plane.", - examples=[None], - ) - # Plane 3 - pvforecast3_surface_tilt: Optional[float] = Field( - default=None, - description="Tilt angle from horizontal plane. Ignored for two-axis tracking.", - examples=[None], - ) - pvforecast3_surface_azimuth: Optional[float] = Field( - default=None, - description="Orientation (azimuth angle) of the (fixed) plane. Clockwise from north (north=0, east=90, south=180, west=270).", - examples=[None], - ) - pvforecast3_userhorizon: Optional[List[float]] = Field( - default=None, - description="Elevation of horizon in degrees, at equally spaced azimuth clockwise from north.", - examples=[None], - ) - pvforecast3_peakpower: Optional[float] = Field( - default=None, description="Nominal power of PV system in kW.", examples=[None] - ) - pvforecast3_pvtechchoice: Optional[str] = Field( - default="crystSi", - description="PV technology. One of 'crystSi', 'CIS', 'CdTe', 'Unknown'.", - examples=[None], - ) - pvforecast3_mountingplace: Optional[str] = Field( - default="free", - description="Type of mounting for PV system. Options are 'free' for free-standing and 'building' for building-integrated.", - examples=[None], - ) - pvforecast3_loss: Optional[float] = Field( - default=14.0, description="Sum of PV system losses in percent", examples=[None] - ) - pvforecast3_trackingtype: Optional[int] = Field( - default=None, - description="Type of suntracking. 0=fixed, 1=single horizontal axis aligned north-south, 2=two-axis tracking, 3=vertical axis tracking, 4=single horizontal axis aligned east-west, 5=single inclined axis aligned north-south.", - examples=[None], - ) - pvforecast3_optimal_surface_tilt: Optional[bool] = Field( - default=False, - description="Calculate the optimum tilt angle. Ignored for two-axis tracking.", - examples=[None], - ) - pvforecast3_optimalangles: Optional[bool] = Field( - default=False, - description="Calculate the optimum tilt and azimuth angles. Ignored for two-axis tracking.", - examples=[None], - ) - pvforecast3_albedo: Optional[float] = Field( - default=None, - description="Proportion of the light hitting the ground that it reflects back.", - examples=[None], - ) - pvforecast3_module_model: Optional[str] = Field( - default=None, description="Model of the PV modules of this plane.", examples=[None] - ) - pvforecast3_inverter_model: Optional[str] = Field( - default=None, description="Model of the inverter of this plane.", examples=[None] - ) - pvforecast3_inverter_paco: Optional[int] = Field( - default=None, description="AC power rating of the inverter. [W]", examples=[None] - ) - pvforecast3_modules_per_string: Optional[int] = Field( - default=None, - description="Number of the PV modules of the strings of this plane.", - examples=[None], - ) - pvforecast3_strings_per_inverter: Optional[int] = Field( - default=None, - description="Number of the strings of the inverter of this plane.", - examples=[None], - ) - # Plane 4 - pvforecast4_surface_tilt: Optional[float] = Field( - default=None, - description="Tilt angle from horizontal plane. Ignored for two-axis tracking.", - examples=[None], - ) - pvforecast4_surface_azimuth: Optional[float] = Field( - default=None, - description="Orientation (azimuth angle) of the (fixed) plane. Clockwise from north (north=0, east=90, south=180, west=270).", - examples=[None], - ) - pvforecast4_userhorizon: Optional[List[float]] = Field( - default=None, - description="Elevation of horizon in degrees, at equally spaced azimuth clockwise from north.", - examples=[None], - ) - pvforecast4_peakpower: Optional[float] = Field( - default=None, description="Nominal power of PV system in kW.", examples=[None] - ) - pvforecast4_pvtechchoice: Optional[str] = Field( - default="crystSi", - description="PV technology. One of 'crystSi', 'CIS', 'CdTe', 'Unknown'.", - examples=[None], - ) - pvforecast4_mountingplace: Optional[str] = Field( - default="free", - description="Type of mounting for PV system. Options are 'free' for free-standing and 'building' for building-integrated.", - examples=[None], - ) - pvforecast4_loss: Optional[float] = Field( - default=14.0, description="Sum of PV system losses in percent", examples=[None] - ) - pvforecast4_trackingtype: Optional[int] = Field( - default=None, - description="Type of suntracking. 0=fixed, 1=single horizontal axis aligned north-south, 2=two-axis tracking, 3=vertical axis tracking, 4=single horizontal axis aligned east-west, 5=single inclined axis aligned north-south.", - examples=[None], - ) - pvforecast4_optimal_surface_tilt: Optional[bool] = Field( - default=False, - description="Calculate the optimum tilt angle. Ignored for two-axis tracking.", - examples=[None], - ) - pvforecast4_optimalangles: Optional[bool] = Field( - default=False, - description="Calculate the optimum tilt and azimuth angles. Ignored for two-axis tracking.", - examples=[None], - ) - pvforecast4_albedo: Optional[float] = Field( - default=None, - description="Proportion of the light hitting the ground that it reflects back.", - examples=[None], - ) - pvforecast4_module_model: Optional[str] = Field( - default=None, description="Model of the PV modules of this plane.", examples=[None] - ) - pvforecast4_inverter_model: Optional[str] = Field( - default=None, description="Model of the inverter of this plane.", examples=[None] - ) - pvforecast4_inverter_paco: Optional[int] = Field( - default=None, description="AC power rating of the inverter. [W]", examples=[None] - ) - pvforecast4_modules_per_string: Optional[int] = Field( - default=None, - description="Number of the PV modules of the strings of this plane.", - examples=[None], - ) - pvforecast4_strings_per_inverter: Optional[int] = Field( - default=None, - description="Number of the strings of the inverter of this plane.", - examples=[None], - ) - # Plane 5 - pvforecast5_surface_tilt: Optional[float] = Field( - default=None, - description="Tilt angle from horizontal plane. Ignored for two-axis tracking.", - examples=[None], - ) - pvforecast5_surface_azimuth: Optional[float] = Field( - default=None, - description="Orientation (azimuth angle) of the (fixed) plane. Clockwise from north (north=0, east=90, south=180, west=270).", - examples=[None], - ) - pvforecast5_userhorizon: Optional[List[float]] = Field( - default=None, - description="Elevation of horizon in degrees, at equally spaced azimuth clockwise from north.", - examples=[None], - ) - pvforecast5_peakpower: Optional[float] = Field( - default=None, description="Nominal power of PV system in kW.", examples=[None] - ) - pvforecast5_pvtechchoice: Optional[str] = Field( - default="crystSi", - description="PV technology. One of 'crystSi', 'CIS', 'CdTe', 'Unknown'.", - examples=[None], - ) - pvforecast5_mountingplace: Optional[str] = Field( - default="free", - description="Type of mounting for PV system. Options are 'free' for free-standing and 'building' for building-integrated.", - examples=[None], - ) - pvforecast5_loss: Optional[float] = Field( - default=14.0, description="Sum of PV system losses in percent", examples=[None] - ) - pvforecast5_trackingtype: Optional[int] = Field( - default=None, - description="Type of suntracking. 0=fixed, 1=single horizontal axis aligned north-south, 2=two-axis tracking, 3=vertical axis tracking, 4=single horizontal axis aligned east-west, 5=single inclined axis aligned north-south.", - examples=[None], - ) - pvforecast5_optimal_surface_tilt: Optional[bool] = Field( - default=False, - description="Calculate the optimum tilt angle. Ignored for two-axis tracking.", - examples=[None], - ) - pvforecast5_optimalangles: Optional[bool] = Field( - default=False, - description="Calculate the optimum tilt and azimuth angles. Ignored for two-axis tracking.", - examples=[None], - ) - pvforecast5_albedo: Optional[float] = Field( - default=None, - description="Proportion of the light hitting the ground that it reflects back.", - examples=[None], - ) - pvforecast5_module_model: Optional[str] = Field( - default=None, description="Model of the PV modules of this plane.", examples=[None] - ) - pvforecast5_inverter_model: Optional[str] = Field( - default=None, description="Model of the inverter of this plane.", examples=[None] - ) - pvforecast5_inverter_paco: Optional[int] = Field( - default=None, description="AC power rating of the inverter. [W]", examples=[None] - ) - pvforecast5_modules_per_string: Optional[int] = Field( - default=None, - description="Number of the PV modules of the strings of this plane.", - examples=[None], - ) - pvforecast5_strings_per_inverter: Optional[int] = Field( - default=None, - description="Number of the strings of the inverter of this plane.", - examples=[None], + description="Plane configuration.", + examples=[get_model_structure_from_examples(PVForecastPlaneSetting, True)], ) - pvforecast_max_planes: ClassVar[int] = 6 # Maximum number of planes that can be set + max_planes: ClassVar[int] = 6 # Maximum number of planes that can be set + + @field_validator("planes") + def validate_planes( + cls, planes: Optional[list[PVForecastPlaneSetting]] + ) -> Optional[list[PVForecastPlaneSetting]]: + if planes is not None and len(planes) > cls.max_planes: + raise ValueError(f"Maximum number of supported planes: {cls.max_planes}.") + return planes provider_settings: Optional[PVForecastImportCommonSettings] = Field( default=None, description="Provider settings", examples=[None] ) - # Computed fields + ## Computed fields @computed_field # type: ignore[prop-decorator] @property - def pvforecast_planes(self) -> List[str]: - """Compute a list of active planes.""" - active_planes = [] - - # Loop through pvforecast0 to pvforecast4 - for i in range(self.pvforecast_max_planes): - plane = f"pvforecast{i}" - tackingtype_attr = f"{plane}_trackingtype" - tilt_attr = f"{plane}_surface_tilt" - azimuth_attr = f"{plane}_surface_azimuth" - - # Check if either attribute is set and add to active planes - if getattr(self, tackingtype_attr, None) == 2: - # Tilt angle from horizontal plane is gnored for two-axis tracking. - if getattr(self, azimuth_attr, None) is not None: - active_planes.append(f"pvforecast{i}") - elif getattr(self, tilt_attr, None) and getattr(self, azimuth_attr, None): - active_planes.append(f"pvforecast{i}") - - return active_planes - - @computed_field # type: ignore[prop-decorator] - @property - def pvforecast_planes_peakpower(self) -> List[float]: + def planes_peakpower(self) -> List[float]: """Compute a list of the peak power per active planes.""" planes_peakpower = [] - for plane in self.pvforecast_planes: - peakpower_attr = f"{plane}_peakpower" - peakpower = getattr(self, peakpower_attr, None) - if peakpower is None: - # TODO calculate peak power from modules/strings - planes_peakpower.append(float(5000)) - else: - planes_peakpower.append(float(peakpower)) + if self.planes: + for plane in self.planes: + peakpower = plane.peakpower + if peakpower is None: + # TODO calculate peak power from modules/strings + planes_peakpower.append(float(5000)) + else: + planes_peakpower.append(float(peakpower)) return planes_peakpower @computed_field # type: ignore[prop-decorator] @property - def pvforecast_planes_azimuth(self) -> List[float]: + def planes_azimuth(self) -> List[float]: """Compute a list of the azimuths per active planes.""" planes_azimuth = [] - for plane in self.pvforecast_planes: - azimuth_attr = f"{plane}_surface_azimuth" - azimuth = getattr(self, azimuth_attr, None) - if azimuth is None: - # TODO Use default - planes_azimuth.append(float(180)) - else: - planes_azimuth.append(float(azimuth)) + if self.planes: + for plane in self.planes: + azimuth = plane.surface_azimuth + if azimuth is None: + # TODO Use default + planes_azimuth.append(float(180)) + else: + planes_azimuth.append(float(azimuth)) return planes_azimuth @computed_field # type: ignore[prop-decorator] @property - def pvforecast_planes_tilt(self) -> List[float]: + def planes_tilt(self) -> List[float]: """Compute a list of the tilts per active planes.""" planes_tilt = [] - for plane in self.pvforecast_planes: - tilt_attr = f"{plane}_surface_tilt" - tilt = getattr(self, tilt_attr, None) - if tilt is None: - # TODO Use default - planes_tilt.append(float(30)) - else: - planes_tilt.append(float(tilt)) + if self.planes: + for plane in self.planes: + tilt = plane.surface_tilt + if tilt is None: + # TODO Use default + planes_tilt.append(float(30)) + else: + planes_tilt.append(float(tilt)) return planes_tilt @computed_field # type: ignore[prop-decorator] @property - def pvforecast_planes_userhorizon(self) -> Any: + def planes_userhorizon(self) -> Any: """Compute a list of the user horizon per active planes.""" planes_userhorizon = [] - for plane in self.pvforecast_planes: - userhorizon_attr = f"{plane}_userhorizon" - userhorizon = getattr(self, userhorizon_attr, None) - if userhorizon is None: - # TODO Use default - planes_userhorizon.append([float(0), float(0)]) - else: - planes_userhorizon.append(userhorizon) + if self.planes: + for plane in self.planes: + userhorizon = plane.userhorizon + if userhorizon is None: + # TODO Use default + planes_userhorizon.append([float(0), float(0)]) + else: + planes_userhorizon.append(userhorizon) return planes_userhorizon @computed_field # type: ignore[prop-decorator] @property - def pvforecast_planes_inverter_paco(self) -> Any: + def planes_inverter_paco(self) -> Any: """Compute a list of the maximum power rating of the inverter per active planes.""" planes_inverter_paco = [] - for plane in self.pvforecast_planes: - inverter_paco_attr = f"{plane}_inverter_paco" - inverter_paco = getattr(self, inverter_paco_attr, None) - if inverter_paco is None: - # TODO Use default - no clipping - planes_inverter_paco.append(25000.0) - else: - planes_inverter_paco.append(float(inverter_paco)) + if self.planes: + for plane in self.planes: + inverter_paco = plane.inverter_paco + if inverter_paco is None: + # TODO Use default - no clipping + planes_inverter_paco.append(25000.0) + else: + planes_inverter_paco.append(float(inverter_paco)) return planes_inverter_paco diff --git a/src/akkudoktoreos/prediction/pvforecastakkudoktor.py b/src/akkudoktoreos/prediction/pvforecastakkudoktor.py index 11877ac..e690d89 100644 --- a/src/akkudoktoreos/prediction/pvforecastakkudoktor.py +++ b/src/akkudoktoreos/prediction/pvforecastakkudoktor.py @@ -22,16 +22,22 @@ Example: }, "pvforecast": { "provider": "PVForecastAkkudoktor", - "pvforecast0_peakpower": 5.0, - "pvforecast0_surface_azimuth": -10, - "pvforecast0_surface_tilt": 7, - "pvforecast0_userhorizon": [20, 27, 22, 20], - "pvforecast0_inverter_paco": 10000, - "pvforecast1_peakpower": 4.8, - "pvforecast1_surface_azimuth": -90, - "pvforecast1_surface_tilt": 7, - "pvforecast1_userhorizon": [30, 30, 30, 50], - "pvforecast1_inverter_paco": 10000, + "planes": [ + { + "peakpower": 5.0, + "surface_azimuth": -10, + "surface_tilt": 7, + "userhorizon": [20, 27, 22, 20], + "inverter_paco": 10000, + }, + { + "peakpower": 4.8, + "surface_azimuth": -90, + "surface_tilt": 7, + "userhorizon": [30, 30, 30, 50], + "inverter_paco": 10000, + } + ] } } @@ -211,19 +217,15 @@ class PVForecastAkkudoktor(PVForecastProvider): f"lon={self.config.prediction.longitude}", ] - for i in range(len(self.config.pvforecast.pvforecast_planes)): + for i in range(len(self.config.pvforecast.planes)): + query_params.append(f"power={int(self.config.pvforecast.planes_peakpower[i] * 1000)}") + query_params.append(f"azimuth={int(self.config.pvforecast.planes_azimuth[i])}") + query_params.append(f"tilt={int(self.config.pvforecast.planes_tilt[i])}") query_params.append( - f"power={int(self.config.pvforecast.pvforecast_planes_peakpower[i] * 1000)}" - ) - query_params.append( - f"azimuth={int(self.config.pvforecast.pvforecast_planes_azimuth[i])}" - ) - query_params.append(f"tilt={int(self.config.pvforecast.pvforecast_planes_tilt[i])}") - query_params.append( - f"powerInverter={int(self.config.pvforecast.pvforecast_planes_inverter_paco[i])}" + f"powerInverter={int(self.config.pvforecast.planes_inverter_paco[i])}" ) horizon_values = ",".join( - str(int(h)) for h in self.config.pvforecast.pvforecast_planes_userhorizon[i] + str(int(h)) for h in self.config.pvforecast.planes_userhorizon[i] ) query_params.append(f"horizont={horizon_values}") @@ -273,7 +275,7 @@ class PVForecastAkkudoktor(PVForecastProvider): `PVForecastAkkudoktorDataRecord`. """ # Assure we have something to request PV power for. - if not self.config.pvforecast.pvforecast_planes: + if not self.config.pvforecast.planes: # No planes for PV error_msg = "Requested PV forecast, but no planes configured." logger.error(f"Configuration error: {error_msg}") @@ -381,26 +383,36 @@ if __name__ == "__main__": }, "pvforecast": { "provider": "PVForecastAkkudoktor", - "pvforecast0_peakpower": 5.0, - "pvforecast0_surface_azimuth": -10, - "pvforecast0_surface_tilt": 7, - "pvforecast0_userhorizon": [20, 27, 22, 20], - "pvforecast0_inverter_paco": 10000, - "pvforecast1_peakpower": 4.8, - "pvforecast1_surface_azimuth": -90, - "pvforecast1_surface_tilt": 7, - "pvforecast1_userhorizon": [30, 30, 30, 50], - "pvforecast1_inverter_paco": 10000, - "pvforecast2_peakpower": 1.4, - "pvforecast2_surface_azimuth": -40, - "pvforecast2_surface_tilt": 60, - "pvforecast2_userhorizon": [60, 30, 0, 30], - "pvforecast2_inverter_paco": 2000, - "pvforecast3_peakpower": 1.6, - "pvforecast3_surface_azimuth": 5, - "pvforecast3_surface_tilt": 45, - "pvforecast3_userhorizon": [45, 25, 30, 60], - "pvforecast3_inverter_paco": 1400, + "planes": [ + { + "peakpower": 5.0, + "surface_azimuth": -10, + "surface_tilt": 7, + "userhorizon": [20, 27, 22, 20], + "inverter_paco": 10000, + }, + { + "peakpower": 4.8, + "surface_azimuth": -90, + "surface_tilt": 7, + "userhorizon": [30, 30, 30, 50], + "inverter_paco": 10000, + }, + { + "peakpower": 1.4, + "surface_azimuth": -40, + "surface_tilt": 60, + "userhorizon": [60, 30, 0, 30], + "inverter_paco": 2000, + }, + { + "peakpower": 1.6, + "surface_azimuth": 5, + "surface_tilt": 45, + "userhorizon": [45, 25, 30, 60], + "inverter_paco": 1400, + }, + ], }, } diff --git a/src/akkudoktoreos/prediction/pvforecastimport.py b/src/akkudoktoreos/prediction/pvforecastimport.py index 89b6551..d04fb5e 100644 --- a/src/akkudoktoreos/prediction/pvforecastimport.py +++ b/src/akkudoktoreos/prediction/pvforecastimport.py @@ -22,24 +22,22 @@ logger = get_logger(__name__) class PVForecastImportCommonSettings(SettingsBaseModel): """Common settings for pvforecast data import from file or JSON string.""" - pvforecastimport_file_path: Optional[Union[str, Path]] = Field( + import_file_path: Optional[Union[str, Path]] = Field( default=None, description="Path to the file to import PV forecast data from.", examples=[None, "/path/to/pvforecast.json"], ) - pvforecastimport_json: Optional[str] = Field( + import_json: Optional[str] = Field( default=None, description="JSON string, dictionary of PV forecast value lists.", examples=['{"pvforecast_ac_power": [0, 8.05, 352.91]}'], ) # Validators - @field_validator("pvforecastimport_file_path", mode="after") + @field_validator("import_file_path", mode="after") @classmethod - def validate_pvforecastimport_file_path( - cls, value: Optional[Union[str, Path]] - ) -> Optional[Path]: + def validate_import_file_path(cls, value: Optional[Union[str, Path]]) -> Optional[Path]: if value is None: return None if isinstance(value, str): @@ -65,13 +63,13 @@ class PVForecastImport(PVForecastProvider, PredictionImportProvider): return "PVForecastImport" def _update_data(self, force_update: Optional[bool] = False) -> None: - if self.config.pvforecast.provider_settings.pvforecastimport_file_path is not None: + if self.config.pvforecast.provider_settings.import_file_path is not None: self.import_from_file( - self.config.pvforecast.provider_settings.pvforecastimport_file_path, + self.config.pvforecast.provider_settings.import_file_path, key_prefix="pvforecast", ) - if self.config.pvforecast.provider_settings.pvforecastimport_json is not None: + if self.config.pvforecast.provider_settings.import_json is not None: self.import_from_json( - self.config.pvforecast.provider_settings.pvforecastimport_json, + self.config.pvforecast.provider_settings.import_json, key_prefix="pvforecast", ) diff --git a/src/akkudoktoreos/utils/docs.py b/src/akkudoktoreos/utils/docs.py new file mode 100644 index 0000000..a469c0b --- /dev/null +++ b/src/akkudoktoreos/utils/docs.py @@ -0,0 +1,42 @@ +from typing import Any + +from pydantic.fields import FieldInfo + +from akkudoktoreos.core.pydantic import PydanticBaseModel + + +def get_example_or_default(field_name: str, field_info: FieldInfo, example_ix: int) -> Any: + """Generate a default value for a field, considering constraints.""" + if field_info.examples is not None: + try: + return field_info.examples[example_ix] + except IndexError: + return field_info.examples[-1] + + if field_info.default is not None: + return field_info.default + + raise NotImplementedError(f"No default or example provided '{field_name}': {field_info}") + + +def get_model_structure_from_examples( + model_class: type[PydanticBaseModel], multiple: bool +) -> list[dict[str, Any]]: + """Create a model instance with default or example values, respecting constraints.""" + example_max_length = 1 + + # Get first field with examples (non-default) to get example_max_length + if multiple: + for _, field_info in model_class.model_fields.items(): + if field_info.examples is not None: + example_max_length = len(field_info.examples) + break + + example_data: list[dict[str, Any]] = [{} for _ in range(example_max_length)] + + for field_name, field_info in model_class.model_fields.items(): + for example_ix in range(example_max_length): + example_data[example_ix][field_name] = get_example_or_default( + field_name, field_info, example_ix + ) + return example_data diff --git a/tests/test_pvforecast.py b/tests/test_pvforecast.py index 2721cd4..04f5bbf 100644 --- a/tests/test_pvforecast.py +++ b/tests/test_pvforecast.py @@ -1,82 +1,75 @@ import pytest -from akkudoktoreos.prediction.pvforecast import PVForecastCommonSettings +from akkudoktoreos.prediction.pvforecast import ( + PVForecastCommonSettings, + PVForecastPlaneSetting, +) @pytest.fixture def settings(): """Fixture that creates an empty PVForecastSettings.""" settings = PVForecastCommonSettings() - - # Check default values for plane 0 - assert settings.pvforecast0_surface_tilt is None - assert settings.pvforecast0_surface_azimuth is None - assert settings.pvforecast0_pvtechchoice == "crystSi" - assert settings.pvforecast0_mountingplace == "free" - assert settings.pvforecast0_trackingtype is None - assert settings.pvforecast0_optimal_surface_tilt is False - assert settings.pvforecast0_optimalangles is False - # Check default values for plane 1 - assert settings.pvforecast1_surface_azimuth is None - assert settings.pvforecast1_pvtechchoice == "crystSi" - assert settings.pvforecast1_mountingplace == "free" - assert settings.pvforecast1_trackingtype is None - assert settings.pvforecast1_optimal_surface_tilt is False - assert settings.pvforecast1_optimalangles is False - - expected_planes: list[str] = [] - assert settings.pvforecast_planes == expected_planes - + assert settings.planes is None return settings -def test_active_planes_detection(settings): - """Test that active planes are correctly detected based on tilt and azimuth.""" - settings.pvforecast1_surface_tilt = 10.0 - settings.pvforecast1_surface_azimuth = 10.0 - settings.pvforecast2_surface_tilt = 20.0 - settings.pvforecast2_surface_azimuth = 20.0 - - expected_planes = ["pvforecast1", "pvforecast2"] - assert settings.pvforecast_planes == expected_planes - - def test_planes_peakpower_computation(settings): """Test computation of peak power for active planes.""" - settings.pvforecast1_surface_tilt = 10.0 - settings.pvforecast1_surface_azimuth = 10.0 - settings.pvforecast1_peakpower = 5.0 - settings.pvforecast2_surface_tilt = 20.0 - settings.pvforecast2_surface_azimuth = 20.0 - settings.pvforecast2_peakpower = 3.5 - settings.pvforecast3_surface_tilt = 30.0 - settings.pvforecast3_surface_azimuth = 30.0 - settings.pvforecast3_modules_per_string = 20 # Should use default 5000W + settings.planes = [ + PVForecastPlaneSetting( + surface_tilt=10.0, + surface_azimuth=10.0, + peakpower=5.0, + ), + PVForecastPlaneSetting( + surface_tilt=20.0, + surface_azimuth=20.0, + peakpower=3.5, + ), + PVForecastPlaneSetting( + surface_tilt=30.0, + surface_azimuth=30.0, + modules_per_string=20, # Should use default 5000W + ), + ] expected_peakpower = [5.0, 3.5, 5000.0] - assert settings.pvforecast_planes_peakpower == expected_peakpower + assert settings.planes_peakpower == expected_peakpower def test_planes_azimuth_computation(settings): """Test computation of azimuth values for active planes.""" - settings.pvforecast1_surface_tilt = 10.0 - settings.pvforecast1_surface_azimuth = 10.0 - settings.pvforecast2_surface_tilt = 20.0 - settings.pvforecast2_surface_azimuth = 20.0 + settings.planes = [ + PVForecastPlaneSetting( + surface_tilt=10.0, + surface_azimuth=10.0, + ), + PVForecastPlaneSetting( + surface_tilt=20.0, + surface_azimuth=20.0, + ), + ] expected_azimuths = [10.0, 20.0] - assert settings.pvforecast_planes_azimuth == expected_azimuths + assert settings.planes_azimuth == expected_azimuths def test_planes_tilt_computation(settings): """Test computation of tilt values for active planes.""" - settings.pvforecast1_surface_tilt = 10.0 - settings.pvforecast1_surface_azimuth = 10.0 - settings.pvforecast2_surface_tilt = 20.0 - settings.pvforecast2_surface_azimuth = 20.0 + settings.planes = [ + PVForecastPlaneSetting( + surface_tilt=10.0, + surface_azimuth=10.0, + ), + PVForecastPlaneSetting( + surface_tilt=20.0, + surface_azimuth=20.0, + ), + ] expected_tilts = [10.0, 20.0] - assert settings.pvforecast_planes_tilt == expected_tilts + assert settings.planes_tilt == expected_tilts def test_planes_userhorizon_computation(settings): @@ -84,116 +77,84 @@ def test_planes_userhorizon_computation(settings): horizon1 = [10.0, 20.0, 30.0] horizon2 = [5.0, 15.0, 25.0] - settings.pvforecast1_surface_tilt = 10.0 - settings.pvforecast1_surface_azimuth = 10.0 - settings.pvforecast1_userhorizon = horizon1 - settings.pvforecast2_surface_tilt = 20.0 - settings.pvforecast2_surface_azimuth = 20.0 - settings.pvforecast2_userhorizon = horizon2 + settings.planes = [ + PVForecastPlaneSetting( + surface_tilt=10.0, + surface_azimuth=10.0, + userhorizon=horizon1, + ), + PVForecastPlaneSetting( + surface_tilt=20.0, + surface_azimuth=20.0, + userhorizon=horizon2, + ), + ] expected_horizons = [horizon1, horizon2] - assert settings.pvforecast_planes_userhorizon == expected_horizons + assert settings.planes_userhorizon == expected_horizons def test_planes_inverter_paco_computation(settings): """Test computation of inverter power rating for active planes.""" - settings.pvforecast1_surface_tilt = 10.0 - settings.pvforecast1_surface_azimuth = 10.0 - settings.pvforecast1_inverter_paco = 6000 - settings.pvforecast2_surface_tilt = 20.0 - settings.pvforecast2_surface_azimuth = 20.0 - settings.pvforecast2_inverter_paco = 4000 + settings.planes = [ + PVForecastPlaneSetting( + surface_tilt=10.0, + surface_azimuth=10.0, + inverter_paco=6000, + ), + PVForecastPlaneSetting( + surface_tilt=20.0, + surface_azimuth=20.0, + inverter_paco=4000, + ), + ] expected_paco = [6000, 4000] - assert settings.pvforecast_planes_inverter_paco == expected_paco - - -def test_non_sequential_plane_numbers(settings): - """Test that non-sequential plane numbers are handled correctly.""" - settings.pvforecast1_surface_tilt = 10.0 - settings.pvforecast1_surface_azimuth = 10.0 - settings.pvforecast1_peakpower = 5.0 - settings.pvforecast3_surface_tilt = 30.0 - settings.pvforecast3_surface_azimuth = 30.0 - settings.pvforecast3_peakpower = 3.5 - settings.pvforecast5_surface_tilt = 50.0 - settings.pvforecast5_surface_azimuth = 50.0 - settings.pvforecast5_peakpower = 2.0 - - expected_planes = ["pvforecast1", "pvforecast3", "pvforecast5"] - assert settings.pvforecast_planes == expected_planes - assert settings.pvforecast_planes_peakpower == [5.0, 3.5, 2.0] + assert settings.planes_inverter_paco == expected_paco def test_mixed_plane_configuration(settings): """Test mixed configuration with some planes having peak power and others having modules.""" - settings.pvforecast1_surface_tilt = 10.0 - settings.pvforecast1_surface_azimuth = 10.0 - settings.pvforecast1_peakpower = 5.0 - settings.pvforecast2_surface_tilt = 20.0 - settings.pvforecast2_surface_azimuth = 20.0 - settings.pvforecast2_modules_per_string = 20 - settings.pvforecast2_strings_per_inverter = 2 - settings.pvforecast4_surface_tilt = 40.0 - settings.pvforecast4_surface_azimuth = 40.0 - settings.pvforecast4_peakpower = 3.0 + settings.planes = [ + PVForecastPlaneSetting( + surface_tilt=10.0, + surface_azimuth=10.0, + peakpower=5.0, + ), + PVForecastPlaneSetting( + surface_tilt=20.0, + surface_azimuth=20.0, + modules_per_string=20, + strings_per_inverter=2, + ), + PVForecastPlaneSetting( + surface_tilt=40.0, + surface_azimuth=40.0, + peakpower=3.0, + ), + ] - expected_planes = ["pvforecast1", "pvforecast2", "pvforecast4"] - assert settings.pvforecast_planes == expected_planes # First plane uses specified peak power, second uses default, third uses specified - assert settings.pvforecast_planes_peakpower == [5.0, 5000.0, 3.0] + assert settings.planes_peakpower == [5.0, 5000.0, 3.0] def test_max_planes_limit(settings): """Test that the maximum number of planes is enforced.""" - assert settings.pvforecast_max_planes == 6 + assert settings.max_planes == 6 # Create settings with more planes than allowed (should only recognize up to max) - plane_settings = {} - for i in range(1, 8): # Try to set up 7 planes, skipping plane 0 - plane_settings[f"pvforecast{i}_peakpower"] = 5.0 + plane_settings = [{"peakpower": 5.0} for _ in range(8)] - settings = PVForecastCommonSettings(**plane_settings) - assert len(settings.pvforecast_planes) <= settings.pvforecast_max_planes + with pytest.raises(ValueError): + PVForecastCommonSettings(planes=plane_settings) -def test_optional_parameters_non_zero_plane(settings): +def test_invalid_plane_settings(): """Test that optional parameters can be None for non-zero planes.""" - settings.pvforecast1_peakpower = 5.0 - settings.pvforecast1_albedo = None - settings.pvforecast1_module_model = None - settings.pvforecast1_userhorizon = None - - assert settings.pvforecast1_albedo is None - assert settings.pvforecast1_module_model is None - assert settings.pvforecast1_userhorizon is None - - -def test_tracking_type_values_non_zero_plane(settings): - """Test valid tracking type values for non-zero planes.""" - valid_types = [0, 1, 2, 3, 4, 5] - - for tracking_type in valid_types: - settings.pvforecast1_peakpower = 5.0 - settings.pvforecast1_trackingtype = tracking_type - assert settings.pvforecast1_trackingtype == tracking_type - - -def test_pv_technology_values_non_zero_plane(settings): - """Test valid PV technology values for non-zero planes.""" - valid_technologies = ["crystSi", "CIS", "CdTe", "Unknown"] - - for tech in valid_technologies: - settings.pvforecast2_peakpower = 5.0 - settings.pvforecast2_pvtechchoice = tech - assert settings.pvforecast2_pvtechchoice == tech - - -def test_mounting_place_values_non_zero_plane(settings): - """Test valid mounting place values for non-zero planes.""" - valid_mounting = ["free", "building"] - - for mounting in valid_mounting: - settings.pvforecast3_peakpower = 5.0 - settings.pvforecast3_mountingplace = mounting - assert settings.pvforecast3_mountingplace == mounting + with pytest.raises(ValueError): + PVForecastPlaneSetting( + peakpower=5.0, + albedo=None, + module_model=None, + userhorizon=None, + ) diff --git a/tests/test_pvforecastakkudoktor.py b/tests/test_pvforecastakkudoktor.py index e21769e..a4f4eca 100644 --- a/tests/test_pvforecastakkudoktor.py +++ b/tests/test_pvforecastakkudoktor.py @@ -33,27 +33,36 @@ def sample_settings(config_eos): }, "pvforecast": { "provider": "PVForecastAkkudoktor", - "pvforecast0_peakpower": 5.0, - "pvforecast0_surface_azimuth": -10, - "pvforecast0_surface_tilt": 7, - "pvforecast0_userhorizon": [20, 27, 22, 20], - "pvforecast0_inverter_paco": 10000, - "pvforecast1_peakpower": 4.8, - "pvforecast1_surface_azimuth": -90, - "pvforecast1_surface_tilt": 7, - "pvforecast1_userhorizon": [30, 30, 30, 50], - "pvforecast1_inverter_paco": 10000, - "pvforecast2_peakpower": 1.4, - "pvforecast2_surface_azimuth": -40, - "pvforecast2_surface_tilt": 60, - "pvforecast2_userhorizon": [60, 30, 0, 30], - "pvforecast2_inverter_paco": 2000, - "pvforecast3_peakpower": 1.6, - "pvforecast3_surface_azimuth": 5, - "pvforecast3_surface_tilt": 45, - "pvforecast3_userhorizon": [45, 25, 30, 60], - "pvforecast3_inverter_paco": 1400, - "pvforecast4_peakpower": None, + "planes": [ + { + "peakpower": 5.0, + "surface_azimuth": -10, + "surface_tilt": 7, + "userhorizon": [20, 27, 22, 20], + "inverter_paco": 10000, + }, + { + "peakpower": 4.8, + "surface_azimuth": -90, + "surface_tilt": 7, + "userhorizon": [30, 30, 30, 50], + "inverter_paco": 10000, + }, + { + "peakpower": 1.4, + "surface_azimuth": -40, + "surface_tilt": 60, + "userhorizon": [60, 30, 0, 30], + "inverter_paco": 2000, + }, + { + "peakpower": 1.6, + "surface_azimuth": 5, + "surface_tilt": 45, + "userhorizon": [45, 25, 30, 60], + "inverter_paco": 1400, + }, + ], }, } diff --git a/tests/test_pvforecastimport.py b/tests/test_pvforecastimport.py index 27ae2c1..9b8f518 100644 --- a/tests/test_pvforecastimport.py +++ b/tests/test_pvforecastimport.py @@ -19,8 +19,8 @@ def provider(sample_import_1_json, config_eos): "pvforecast": { "provider": "PVForecastImport", "provider_settings": { - "pvforecastimport_file_path": str(FILE_TESTDATA_PVFORECASTIMPORT_1_JSON), - "pvforecastimport_json": json.dumps(sample_import_1_json), + "import_file_path": str(FILE_TESTDATA_PVFORECASTIMPORT_1_JSON), + "import_json": json.dumps(sample_import_1_json), }, } } @@ -55,7 +55,7 @@ def test_invalid_provider(provider, config_eos): "pvforecast": { "provider": "", "provider_settings": { - "pvforecastimport_file_path": str(FILE_TESTDATA_PVFORECASTIMPORT_1_JSON), + "import_file_path": str(FILE_TESTDATA_PVFORECASTIMPORT_1_JSON), }, } } @@ -86,11 +86,11 @@ def test_import(provider, sample_import_1_json, start_datetime, from_file, confi ems_eos = get_ems() ems_eos.set_start_datetime(to_datetime(start_datetime, in_timezone="Europe/Berlin")) if from_file: - config_eos.pvforecast.provider_settings.pvforecastimport_json = None - assert config_eos.pvforecast.provider_settings.pvforecastimport_json is None + config_eos.pvforecast.provider_settings.import_json = None + assert config_eos.pvforecast.provider_settings.import_json is None else: - config_eos.pvforecast.provider_settings.pvforecastimport_file_path = None - assert config_eos.pvforecast.provider_settings.pvforecastimport_file_path is None + config_eos.pvforecast.provider_settings.import_file_path = None + assert config_eos.pvforecast.provider_settings.import_file_path is None provider.clear() # Call the method