diff --git a/changelog.md b/changelog.md index ad7e680..20c4498 100644 --- a/changelog.md +++ b/changelog.md @@ -8,7 +8,14 @@ * Added basic client methods `get_ingestor_run` and `get_ingestor_run_list` to retrieve the records of previous ingestor runs. ### Enhancements -* None. + +* Added optional `generator_config` argument to `run_hosting_capacity_calibration`. This allows the user to override the + default values in the `WorkPackageConfig` used by calibration. Note: The following fields cannot be overridden during + calibration: GeneratorConfig.model.calibration, GeneratorConfig.model.meter_placement_config, + GeneratorConfig.solve.step_size_minutes, and GeneratorConfig.raw_results. +* Added optional `transformer_tap_settings` argument to `run_hosting_capacity_calibration`. This is the equivalent to supplying a `generator_config` + with `generator_config.model.transformer_tap_settings` set. If `transformer_tap_settings` is supplied, it will take precedence over any `transformer_tap_settings` + configured in the `generator_config`. ### Fixes * None. diff --git a/src/zepben/eas/client/eas_client.py b/src/zepben/eas/client/eas_client.py index 8eb9885..1dee151 100644 --- a/src/zepben/eas/client/eas_client.py +++ b/src/zepben/eas/client/eas_client.py @@ -23,7 +23,8 @@ from zepben.eas.client.study import Study from zepben.eas.client.ingestor import IngestorConfigInput, IngestorRunsFilterInput, IngestorRunsSortCriteriaInput from zepben.eas.client.util import construct_url -from zepben.eas.client.work_package import WorkPackageConfig, FixedTime, TimePeriod, ForecastConfig, FeederConfigs +from zepben.eas.client.work_package import WorkPackageConfig, FixedTime, TimePeriod, ForecastConfig, FeederConfigs, \ + GeneratorConfig, ModelConfig __all__ = ["EasClient"] @@ -1044,42 +1045,149 @@ async def async_get_ingestor_run_list(self, query_filter: Optional[IngestorRunsF else: raise response.raise_for_status() - def run_hosting_capacity_calibration(self, calibration_name: str, local_calibration_time: Optional[str] = None, feeders: Optional[List[str]] = None): + def run_hosting_capacity_calibration(self, calibration_name: str, local_calibration_time: datetime, + feeders: Optional[List[str]] = None, + transformer_tap_settings: Optional[str] = None, + generator_config: Optional[GeneratorConfig] = None): """ Send request to run hosting capacity calibration :param calibration_name: A string representation of the calibration name - :param local_calibration_time: A string representation of the calibration time, in model time. + :param local_calibration_time: A datetime representation of the calibration time, in the timezone of your pqv data ("model time"). :param feeders: A list of feeder ID's to run the calibration over. If not supplied then the calibration is run over all feeders in the network. + :param transformer_tap_settings: A set of transformer tap settings to apply before running the calibration work package. + If provided, this will take precedence over any 'transformer_tap_settings' supplied in via the generator_config parameter + :param generator_config: A `GeneratorConfig` object that overrides the default values in the `WorkPackageConfig` used by calibration. + Note: The following fields cannot be overridden during calibration: generator_config.model.calibration, generator_config.model.meter_placement_config, generator_config.solve.step_size_minutes, and generator_config.raw_results. + + :return: The HTTP response received from the Evolve App Server after attempting to run the calibration """ return get_event_loop().run_until_complete( - self.async_run_hosting_capacity_calibration(calibration_name, local_calibration_time, feeders)) + self.async_run_hosting_capacity_calibration(calibration_name, local_calibration_time, feeders, + transformer_tap_settings, + generator_config)) - async def async_run_hosting_capacity_calibration(self, calibration_name: str, calibration_time_local: datetime, feeders: Optional[List[str]] = None): + async def async_run_hosting_capacity_calibration(self, calibration_name: str, + calibration_time_local: datetime, + feeders: Optional[List[str]] = None, + transformer_tap_settings: Optional[str] = None, + generator_config: Optional[GeneratorConfig] = None): """ Send asynchronous request to run hosting capacity calibration :param calibration_name: A string representation of the calibration name - :param calibration_time_local: a datetime representation of the calibration time, in the timezone of your pqv data ("model time"). + :param calibration_time_local: A datetime representation of the calibration time, in the timezone of your pqv data ("model time"). :param feeders: A list of feeder ID's to run the calibration over. If not supplied then the calibration is run over all feeders in the network. + :param transformer_tap_settings: A set of transformer tap settings to apply before running the calibration work package. + If provided, this will take precedence over any 'transformer_tap_settings' supplied in via the generator_config parameter + :param generator_config: A `GeneratorConfig` object that overrides the default values in the `WorkPackageConfig` used by calibration. + Note: The following fields cannot be overridden during calibration: generator_config.model.calibration, generator_config.model.meter_placement_config, generator_config.solve.step_size_minutes, and generator_config.raw_results. + :return: The HTTP response received from the Evolve App Server after attempting to run the calibration """ # Only replace microsecond, as in database we only have down to second precision. # tzinfo will be whatever the user passed through, which should be the timezone of their load data. parsed_time = calibration_time_local.replace(microsecond=0, tzinfo=None) + + if transformer_tap_settings: + if generator_config: + if generator_config.model: + generator_config.model.transformer_tap_settings = transformer_tap_settings + else: + generator_config.model = ModelConfig(transformer_tap_settings=transformer_tap_settings) + else: + generator_config = GeneratorConfig(model=ModelConfig(transformer_tap_settings=transformer_tap_settings)) + with warnings.catch_warnings(): if not self._verify_certificate: warnings.filterwarnings("ignore", category=InsecureRequestWarning) json = { "query": """ - mutation runCalibration($calibrationName: String!, $calibrationTimeLocal: LocalDateTime, $feeders: [String!]) { - runCalibration(calibrationName: $calibrationName, calibrationTimeLocal: $calibrationTimeLocal, feeders: $feeders) + mutation runCalibration($calibrationName: String!, $calibrationTimeLocal: LocalDateTime, $feeders: [String!], $generatorConfig: HcGeneratorConfigInput) { + runCalibration(calibrationName: $calibrationName, calibrationTimeLocal: $calibrationTimeLocal, feeders: $feeders, generatorConfig: $generatorConfig) } """, "variables": { "calibrationName": calibration_name, "calibrationTimeLocal": parsed_time.isoformat(), - "feeders": feeders + "feeders": feeders, + "generatorConfig": generator_config and { + "model": generator_config.model and { + "vmPu": generator_config.model.vm_pu, + "loadVMinPu": generator_config.model.load_vmin_pu, + "loadVMaxPu": generator_config.model.load_vmax_pu, + "genVMinPu": generator_config.model.gen_vmin_pu, + "genVMaxPu": generator_config.model.gen_vmax_pu, + "loadModel": generator_config.model.load_model, + "collapseSWER": generator_config.model.collapse_swer, + "calibration": generator_config.model.calibration, + "pFactorBaseExports": generator_config.model.p_factor_base_exports, + "pFactorForecastPv": generator_config.model.p_factor_forecast_pv, + "pFactorBaseImports": generator_config.model.p_factor_base_imports, + "fixSinglePhaseLoads": generator_config.model.fix_single_phase_loads, + "maxSinglePhaseLoad": generator_config.model.max_single_phase_load, + "fixOverloadingConsumers": generator_config.model.fix_overloading_consumers, + "maxLoadTxRatio": generator_config.model.max_load_tx_ratio, + "maxGenTxRatio": generator_config.model.max_gen_tx_ratio, + "fixUndersizedServiceLines": generator_config.model.fix_undersized_service_lines, + "maxLoadServiceLineRatio": generator_config.model.max_load_service_line_ratio, + "maxLoadLvLineRatio": generator_config.model.max_load_lv_line_ratio, + "collapseLvNetworks": generator_config.model.collapse_lv_networks, + "feederScenarioAllocationStrategy": generator_config.model.feeder_scenario_allocation_strategy and generator_config.model.feeder_scenario_allocation_strategy.name, + "closedLoopVRegEnabled": generator_config.model.closed_loop_v_reg_enabled, + "closedLoopVRegReplaceAll": generator_config.model.closed_loop_v_reg_replace_all, + "closedLoopVRegSetPoint": generator_config.model.closed_loop_v_reg_set_point, + "closedLoopVBand": generator_config.model.closed_loop_v_band, + "closedLoopTimeDelay": generator_config.model.closed_loop_time_delay, + "closedLoopVLimit": generator_config.model.closed_loop_v_limit, + "defaultTapChangerTimeDelay": generator_config.model.default_tap_changer_time_delay, + "defaultTapChangerSetPointPu": generator_config.model.default_tap_changer_set_point_pu, + "defaultTapChangerBand": generator_config.model.default_tap_changer_band, + "splitPhaseDefaultLoadLossPercentage": generator_config.model.split_phase_default_load_loss_percentage, + "splitPhaseLVKV": generator_config.model.split_phase_lv_kv, + "swerVoltageToLineVoltage": generator_config.model.swer_voltage_to_line_voltage, + "loadPlacement": generator_config.model.load_placement and generator_config.model.load_placement.name, + "loadIntervalLengthHours": generator_config.model.load_interval_length_hours, + "meterPlacementConfig": generator_config.model.meter_placement_config and { + "feederHead": generator_config.model.meter_placement_config.feeder_head, + "distTransformers": generator_config.model.meter_placement_config.dist_transformers, + "switchMeterPlacementConfigs": generator_config.model.meter_placement_config.switch_meter_placement_configs and [ + { + "meterSwitchClass": spc.meter_switch_class and spc.meter_switch_class.name, + "namePattern": spc.name_pattern + } for spc in + generator_config.model.meter_placement_config.switch_meter_placement_configs + ], + "energyConsumerMeterGroup": generator_config.model.meter_placement_config.energy_consumer_meter_group + }, + "seed": generator_config.model.seed, + "defaultLoadWatts": generator_config.model.default_load_watts, + "defaultGenWatts": generator_config.model.default_gen_watts, + "defaultLoadVar": generator_config.model.default_load_var, + "defaultGenVar": generator_config.model.default_gen_var, + "transformerTapSettings": generator_config.model.transformer_tap_settings, + "ctPrimScalingFactor": generator_config.model.ct_prim_scaling_factor, + }, + "solve": generator_config.solve and { + "normVMinPu": generator_config.solve.norm_vmin_pu, + "normVMaxPu": generator_config.solve.norm_vmax_pu, + "emergVMinPu": generator_config.solve.emerg_vmin_pu, + "emergVMaxPu": generator_config.solve.emerg_vmax_pu, + "baseFrequency": generator_config.solve.base_frequency, + "voltageBases": generator_config.solve.voltage_bases, + "maxIter": generator_config.solve.max_iter, + "maxControlIter": generator_config.solve.max_control_iter, + "mode": generator_config.solve.mode and generator_config.solve.mode.name, + "stepSizeMinutes": generator_config.solve.step_size_minutes + }, + "rawResults": generator_config.raw_results and { + "energyMeterVoltagesRaw": generator_config.raw_results.energy_meter_voltages_raw, + "energyMetersRaw": generator_config.raw_results.energy_meters_raw, + "resultsPerMeter": generator_config.raw_results.results_per_meter, + "overloadsRaw": generator_config.raw_results.overloads_raw, + "voltageExceptionsRaw": generator_config.raw_results.voltage_exceptions_raw + } + } } } @@ -1185,14 +1293,17 @@ async def async_get_hosting_capacity_calibration_sets(self): else: response.raise_for_status() - def get_transformer_tap_settings(self, calibration_id: str, feeder: Optional[str] = None, transformer_mrid: Optional[str] = None): + def get_transformer_tap_settings(self, calibration_id: str, feeder: Optional[str] = None, + transformer_mrid: Optional[str] = None): """ Retrieve distribution transformer tap settings from a calibration set in the hosting capacity input database. :return: The HTTP response received from the Evolve App Server after requesting transformer tap settings for the calibration id """ - return get_event_loop().run_until_complete(self.async_get_transformer_tap_settings(calibration_id, feeder, transformer_mrid)) + return get_event_loop().run_until_complete( + self.async_get_transformer_tap_settings(calibration_id, feeder, transformer_mrid)) - async def async_get_transformer_tap_settings(self, calibration_id: str, feeder: Optional[str] = None, transformer_mrid: Optional[str] = None): + async def async_get_transformer_tap_settings(self, calibration_id: str, feeder: Optional[str] = None, + transformer_mrid: Optional[str] = None): """ Retrieve distribution transformer tap settings from a calibration set in the hosting capacity input database. :return: The HTTP response received from the Evolve App Server after requesting transformer tap settings for the calibration id diff --git a/test/test_eas_client.py b/test/test_eas_client.py index 65e96ec..b37c87f 100644 --- a/test/test_eas_client.py +++ b/test/test_eas_client.py @@ -611,8 +611,11 @@ def hosting_capacity_run_calibration_request_handler(request): actual_body = json.loads(request.data.decode()) query = " ".join(actual_body['query'].split()) - assert query == "mutation runCalibration($calibrationName: String!, $calibrationTimeLocal: LocalDateTime, $feeders: [String!]) { runCalibration(calibrationName: $calibrationName, calibrationTimeLocal: $calibrationTimeLocal, feeders: $feeders) }" - assert actual_body['variables'] == {"calibrationName": "TEST CALIBRATION", "calibrationTimeLocal": datetime(2025, month=7, day=12).isoformat(), "feeders": None} + assert query == "mutation runCalibration($calibrationName: String!, $calibrationTimeLocal: LocalDateTime, $feeders: [String!], $generatorConfig: HcGeneratorConfigInput) { runCalibration(calibrationName: $calibrationName, calibrationTimeLocal: $calibrationTimeLocal, feeders: $feeders, generatorConfig: $generatorConfig) }" + assert actual_body['variables'] == {"calibrationName": "TEST CALIBRATION", + "calibrationTimeLocal": datetime(2025, month=7, day=12).isoformat(), + "feeders": None, 'generatorConfig': None + } return Response(json.dumps({"result": "success"}), status=200, content_type="application/json") @@ -718,10 +721,57 @@ def hosting_capacity_run_calibration_with_calibration_time_request_handler(reque actual_body = json.loads(request.data.decode()) query = " ".join(actual_body['query'].split()) - assert query == "mutation runCalibration($calibrationName: String!, $calibrationTimeLocal: LocalDateTime, $feeders: [String!]) { runCalibration(calibrationName: $calibrationName, calibrationTimeLocal: $calibrationTimeLocal, feeders: $feeders) }" + assert query == "mutation runCalibration($calibrationName: String!, $calibrationTimeLocal: LocalDateTime, $feeders: [String!], $generatorConfig: HcGeneratorConfigInput) { runCalibration(calibrationName: $calibrationName, calibrationTimeLocal: $calibrationTimeLocal, feeders: $feeders, generatorConfig: $generatorConfig) }" assert actual_body['variables'] == {"calibrationName": "TEST CALIBRATION", - "calibrationTimeLocal": datetime(1902, month=1, day=28, hour=0, minute=0, second=20).isoformat(), - "feeders": ["one", "two"]} + "calibrationTimeLocal": datetime(1902, month=1, day=28, hour=0, minute=0, + second=20).isoformat(), + "feeders": ["one", "two"], + "generatorConfig": {'model': {'calibration': None, + 'closedLoopTimeDelay': None, + 'closedLoopVBand': None, + 'closedLoopVLimit': None, + 'closedLoopVRegEnabled': None, + 'closedLoopVRegReplaceAll': None, + 'closedLoopVRegSetPoint': None, + 'collapseLvNetworks': None, + 'collapseSWER': None, + 'ctPrimScalingFactor': None, + 'defaultGenVar': None, + 'defaultGenWatts': None, + 'defaultLoadVar': None, + 'defaultLoadWatts': None, + 'defaultTapChangerBand': None, + 'defaultTapChangerSetPointPu': None, + 'defaultTapChangerTimeDelay': None, + 'feederScenarioAllocationStrategy': None, + 'fixOverloadingConsumers': None, + 'fixSinglePhaseLoads': None, + 'fixUndersizedServiceLines': None, + 'genVMaxPu': None, + 'genVMinPu': None, + 'loadIntervalLengthHours': None, + 'loadModel': None, + 'loadPlacement': None, + 'loadVMaxPu': None, + 'loadVMinPu': None, + 'maxGenTxRatio': None, + 'maxLoadLvLineRatio': None, + 'maxLoadServiceLineRatio': None, + 'maxLoadTxRatio': None, + 'maxSinglePhaseLoad': None, + 'meterPlacementConfig': None, + 'pFactorBaseExports': None, + 'pFactorBaseImports': None, + 'pFactorForecastPv': None, + 'seed': None, + 'splitPhaseDefaultLoadLossPercentage': None, + 'splitPhaseLVKV': None, + 'swerVoltageToLineVoltage': None, + 'transformerTapSettings': 'test_tap_settings', + 'vmPu': None}, + 'rawResults': None, + 'solve': None} + } return Response(json.dumps({"result": "success"}), status=200, content_type="application/json") @@ -733,12 +783,227 @@ def test_run_hosting_capacity_calibration_with_calibration_time_no_verify_succes verify_certificate=False ) - httpserver.expect_oneshot_request("/api/graphql").respond_with_handler(hosting_capacity_run_calibration_with_calibration_time_request_handler) - res = eas_client.run_hosting_capacity_calibration("TEST CALIBRATION", datetime(1902, month=1, day=28, hour=0, minute=0, second=20), ["one", "two"]) + httpserver.expect_oneshot_request("/api/graphql").respond_with_handler( + hosting_capacity_run_calibration_with_calibration_time_request_handler) + res = eas_client.run_hosting_capacity_calibration("TEST CALIBRATION", + datetime(1902, month=1, day=28, hour=0, minute=0, second=20), + ["one", "two"], + generator_config=GeneratorConfig(model=ModelConfig( + transformer_tap_settings="test_tap_settings" + )) + ) httpserver.check_assertions() assert res == {"result": "success"} +def test_run_hosting_capacity_calibration_with_explicit_transformer_tap_settings_no_generator_config(httpserver: HTTPServer): + eas_client = EasClient( + LOCALHOST, + httpserver.port, + verify_certificate=False + ) + + httpserver.expect_oneshot_request("/api/graphql").respond_with_handler( + hosting_capacity_run_calibration_with_calibration_time_request_handler) + res = eas_client.run_hosting_capacity_calibration("TEST CALIBRATION", + datetime(1902, month=1, day=28, hour=0, minute=0, second=20), + ["one", "two"], + transformer_tap_settings="test_tap_settings" + ) + httpserver.check_assertions() + assert res == {"result": "success"} + + +def hosting_capacity_run_calibration_with_generator_config_request_handler(request): + actual_body = json.loads(request.data.decode()) + query = " ".join(actual_body['query'].split()) + + assert query == "mutation runCalibration($calibrationName: String!, $calibrationTimeLocal: LocalDateTime, $feeders: [String!], $generatorConfig: HcGeneratorConfigInput) { runCalibration(calibrationName: $calibrationName, calibrationTimeLocal: $calibrationTimeLocal, feeders: $feeders, generatorConfig: $generatorConfig) }" + assert actual_body['variables'] == {"calibrationName": "TEST CALIBRATION", + "calibrationTimeLocal": datetime(1902, month=1, day=28, hour=0, minute=0, + second=20).isoformat(), + "feeders": ["one", "two"], + "generatorConfig": {'model': {'calibration': None, + 'closedLoopTimeDelay': None, + 'closedLoopVBand': None, + 'closedLoopVLimit': None, + 'closedLoopVRegEnabled': None, + 'closedLoopVRegReplaceAll': None, + 'closedLoopVRegSetPoint': None, + 'collapseLvNetworks': None, + 'collapseSWER': None, + 'ctPrimScalingFactor': None, + 'defaultGenVar': None, + 'defaultGenWatts': None, + 'defaultLoadVar': None, + 'defaultLoadWatts': None, + 'defaultTapChangerBand': None, + 'defaultTapChangerSetPointPu': None, + 'defaultTapChangerTimeDelay': None, + 'feederScenarioAllocationStrategy': None, + 'fixOverloadingConsumers': None, + 'fixSinglePhaseLoads': None, + 'fixUndersizedServiceLines': None, + 'genVMaxPu': None, + 'genVMinPu': None, + 'loadIntervalLengthHours': None, + 'loadModel': None, + 'loadPlacement': None, + 'loadVMaxPu': None, + 'loadVMinPu': None, + 'maxGenTxRatio': None, + 'maxLoadLvLineRatio': None, + 'maxLoadServiceLineRatio': None, + 'maxLoadTxRatio': None, + 'maxSinglePhaseLoad': None, + 'meterPlacementConfig': None, + 'pFactorBaseExports': None, + 'pFactorBaseImports': None, + 'pFactorForecastPv': None, + 'seed': None, + 'splitPhaseDefaultLoadLossPercentage': None, + 'splitPhaseLVKV': None, + 'swerVoltageToLineVoltage': None, + 'transformerTapSettings': 'test_tap_settings', + 'vmPu': None + }, + 'rawResults': None, + 'solve': {'baseFrequency': None, + 'emergVMaxPu': None, + 'emergVMinPu': None, + 'maxControlIter': None, + 'maxIter': None, + 'mode': None, + 'normVMaxPu': 23.9, + 'normVMinPu': None, + 'stepSizeMinutes': None, + 'voltageBases': None + } + } + } + + return Response(json.dumps({"result": "success"}), status=200, content_type="application/json") + + +def test_run_hosting_capacity_calibration_with_explicit_transformer_tap_settings_partial_generator_config(httpserver: HTTPServer): + eas_client = EasClient( + LOCALHOST, + httpserver.port, + verify_certificate=False + ) + + httpserver.expect_oneshot_request("/api/graphql").respond_with_handler( + hosting_capacity_run_calibration_with_generator_config_request_handler) + res = eas_client.run_hosting_capacity_calibration("TEST CALIBRATION", + datetime(1902, month=1, day=28, hour=0, minute=0, second=20), + ["one", "two"], + transformer_tap_settings="test_tap_settings", + generator_config=GeneratorConfig(solve=SolveConfig(norm_vmax_pu=23.9)) + ) + httpserver.check_assertions() + assert res == {"result": "success"} + + +def hosting_capacity_run_calibration_with_partial_model_config_request_handler(request): + actual_body = json.loads(request.data.decode()) + query = " ".join(actual_body['query'].split()) + + assert query == "mutation runCalibration($calibrationName: String!, $calibrationTimeLocal: LocalDateTime, $feeders: [String!], $generatorConfig: HcGeneratorConfigInput) { runCalibration(calibrationName: $calibrationName, calibrationTimeLocal: $calibrationTimeLocal, feeders: $feeders, generatorConfig: $generatorConfig) }" + assert actual_body['variables'] == {"calibrationName": "TEST CALIBRATION", + "calibrationTimeLocal": datetime(1902, month=1, day=28, hour=0, minute=0, + second=20).isoformat(), + "feeders": ["one", "two"], + "generatorConfig": {'model': {'calibration': None, + 'closedLoopTimeDelay': None, + 'closedLoopVBand': None, + 'closedLoopVLimit': None, + 'closedLoopVRegEnabled': None, + 'closedLoopVRegReplaceAll': None, + 'closedLoopVRegSetPoint': None, + 'collapseLvNetworks': None, + 'collapseSWER': None, + 'ctPrimScalingFactor': None, + 'defaultGenVar': None, + 'defaultGenWatts': None, + 'defaultLoadVar': None, + 'defaultLoadWatts': None, + 'defaultTapChangerBand': None, + 'defaultTapChangerSetPointPu': None, + 'defaultTapChangerTimeDelay': None, + 'feederScenarioAllocationStrategy': None, + 'fixOverloadingConsumers': None, + 'fixSinglePhaseLoads': None, + 'fixUndersizedServiceLines': None, + 'genVMaxPu': None, + 'genVMinPu': None, + 'loadIntervalLengthHours': None, + 'loadModel': None, + 'loadPlacement': None, + 'loadVMaxPu': None, + 'loadVMinPu': None, + 'maxGenTxRatio': None, + 'maxLoadLvLineRatio': None, + 'maxLoadServiceLineRatio': None, + 'maxLoadTxRatio': None, + 'maxSinglePhaseLoad': None, + 'meterPlacementConfig': None, + 'pFactorBaseExports': None, + 'pFactorBaseImports': None, + 'pFactorForecastPv': None, + 'seed': None, + 'splitPhaseDefaultLoadLossPercentage': None, + 'splitPhaseLVKV': None, + 'swerVoltageToLineVoltage': None, + 'transformerTapSettings': 'test_tap_settings', + 'vmPu': 123.4 + }, + 'rawResults': None, + 'solve': None + } + } + + return Response(json.dumps({"result": "success"}), status=200, content_type="application/json") + + +def test_run_hosting_capacity_calibration_with_explicit_transformer_tap_settings_partial_model_config(httpserver: HTTPServer): + eas_client = EasClient( + LOCALHOST, + httpserver.port, + verify_certificate=False + ) + + httpserver.expect_oneshot_request("/api/graphql").respond_with_handler( + hosting_capacity_run_calibration_with_partial_model_config_request_handler) + res = eas_client.run_hosting_capacity_calibration("TEST CALIBRATION", + datetime(1902, month=1, day=28, hour=0, minute=0, second=20), + ["one", "two"], + transformer_tap_settings="test_tap_settings", + generator_config=GeneratorConfig(model=ModelConfig(vm_pu=123.4)) + ) + httpserver.check_assertions() + assert res == {"result": "success"} + + +def test_run_hosting_capacity_calibration_with_explicit_transformer_tap_settings(httpserver: HTTPServer): + eas_client = EasClient( + LOCALHOST, + httpserver.port, + verify_certificate=False + ) + + httpserver.expect_oneshot_request("/api/graphql").respond_with_handler( + hosting_capacity_run_calibration_with_calibration_time_request_handler) + res = eas_client.run_hosting_capacity_calibration("TEST CALIBRATION", + datetime(1902, month=1, day=28, hour=0, minute=0, second=20), + ["one", "two"], + transformer_tap_settings="test_tap_settings", + generator_config=GeneratorConfig(model=ModelConfig( + transformer_tap_settings="this_should_be_over_written" + )) + ) + httpserver.check_assertions() + assert res == {"result": "success"} + def get_hosting_capacity_calibration_sets_request_handler(request): actual_body = json.loads(request.data.decode()) query = " ".join(actual_body['query'].split())