diff --git a/python/examples/print_transient_ratings.py b/python/examples/print_transient_ratings.py new file mode 100644 index 0000000..cc91a61 --- /dev/null +++ b/python/examples/print_transient_ratings.py @@ -0,0 +1,44 @@ +import logging + +from heimdall_api_client.client import HeimdallApiClient + +logging.basicConfig(level=logging.WARN) + +client = HeimdallApiClient( + client_id="your_client_id", + client_secret="your_client_secret", +) + +assets = client.get_assets() +grid_owner = assets.data.grid_owners[0] + +print(f"\nGrid Owner: {grid_owner.name}\n") + +for facility in grid_owner.facilities: + print(f"Facility: {facility.name}") + + if facility.line: + try: + line_response = client.get_latest_line_transient_rating(line_id=facility.line.id) + line_transient_rating = line_response.data.line_transient_rating + print(f" {line_response.data.metric}, timestamp {line_transient_rating.timestamp}:") + for rating in line_transient_rating.ratings: + print(f" {rating.duration_minutes} min: {rating.value} {line_response.data.unit}") + except Exception as e: + print(f" Failed to fetch line transient rating for line '{facility.line.name}': {e}") + + try: + circuit_response = client.get_latest_circuit_transient_rating(facility_id=facility.id) + circuit_transient_rating = circuit_response.data.circuit_transient_rating + print(f" {circuit_response.data.metric}, timestamp {circuit_transient_rating.timestamp}:") + for rating in circuit_transient_rating.ratings: + # A null limiting component id means the line transient rating is the binding constraint. + limiting_component = rating.limiting_component_id or "none" + print( + f" {rating.duration_minutes} min: {rating.value} {circuit_response.data.unit}, " + f"limited by {limiting_component}" + ) + except Exception as e: + print(f" Failed to fetch circuit transient rating for facility '{facility.name}': {e}") + + print() diff --git a/python/heimdall_api_client/capacity_monitoring.py b/python/heimdall_api_client/capacity_monitoring.py index 5c335a5..df0c885 100644 --- a/python/heimdall_api_client/capacity_monitoring.py +++ b/python/heimdall_api_client/capacity_monitoring.py @@ -18,6 +18,9 @@ from heimdall_api_client.capacity_monitoring_api_client.api.line import ( capacity_monitoring_v1_lines_get_latest_heimdall_dlr_forecasts as get_latest_dlr_forecasts, ) +from heimdall_api_client.capacity_monitoring_api_client.api.line import ( + capacity_monitoring_v1_lines_get_latest_transient_rating as get_latest_line_transient_rating_endpoint, +) from heimdall_api_client.capacity_monitoring_api_client.models.quantity import Quantity from heimdall_api_client.capacity_monitoring_api_client.types import UNSET from heimdall_api_client.errors import HeimdallApiError, body_preview @@ -32,6 +35,9 @@ from heimdall_api_client.capacity_monitoring_api_client.models.capacity_monitoring_v1_facilities_get_latest_circuit_rating_response_200 import ( # noqa: E501 CapacityMonitoringV1FacilitiesGetLatestCircuitRatingResponse200, ) + from heimdall_api_client.capacity_monitoring_api_client.models.capacity_monitoring_v1_facilities_get_latest_circuit_transient_rating_response_200 import ( # noqa: E501 + CapacityMonitoringV1FacilitiesGetLatestCircuitTransientRatingResponse200, + ) from heimdall_api_client.capacity_monitoring_api_client.models.capacity_monitoring_v1_lines_get_heimdall_aars_response_200 import ( # noqa: E501 CapacityMonitoringV1LinesGetHeimdallAarsResponse200, ) @@ -50,6 +56,9 @@ from heimdall_api_client.capacity_monitoring_api_client.models.capacity_monitoring_v1_lines_get_latest_heimdall_dlr_response_200 import ( # noqa: E501 CapacityMonitoringV1LinesGetLatestHeimdallDlrResponse200, ) + from heimdall_api_client.capacity_monitoring_api_client.models.capacity_monitoring_v1_lines_get_latest_transient_rating_response_200 import ( # noqa: E501 + CapacityMonitoringV1LinesGetLatestTransientRatingResponse200, + ) def get_latest_heimdall_dlr( @@ -96,6 +105,34 @@ def get_latest_heimdall_aar( return response.parsed +def get_latest_line_transient_rating( + client: AuthenticatedClient, + line_id: UUID, + region: str, + quantity: Quantity | str | None = None, + since: datetime.datetime | None = None, +) -> CapacityMonitoringV1LinesGetLatestTransientRatingResponse200: + quantity_value = UNSET + if quantity is not None: + quantity_value = quantity if isinstance(quantity, Quantity) else Quantity(quantity) + + response = get_latest_line_transient_rating_endpoint.sync_detailed( + client=client, + line_id=line_id, + x_region=region, + quantity=quantity_value, + since=UNSET if since is None else as_zulu(since), + ) + if response.status_code != 200: + status = int(response.status_code) + raise HeimdallApiError( + f"Error fetching latest line transient rating: {status} {response.status_code.phrase}" + f" - {body_preview(response.content)}", + status_code=status, + ) + return response.parsed + + def get_latest_heimdall_dlr_forecasts( client: AuthenticatedClient, line_id: UUID, region: str ) -> CapacityMonitoringV1LinesGetLatestHeimdallDlrForecastsResponse200: @@ -150,6 +187,38 @@ def get_latest_circuit_ratring( return response.parsed +def get_latest_circuit_transient_rating( + client: AuthenticatedClient, + facility_id: UUID, + x_region: str, + quantity: Quantity | str | None = None, + since: datetime.datetime | None = None, +) -> CapacityMonitoringV1FacilitiesGetLatestCircuitTransientRatingResponse200: + from heimdall_api_client.capacity_monitoring_api_client.api.facility import ( + capacity_monitoring_v1_facilities_get_latest_circuit_transient_rating as _get_latest_circuit_transient_rating, + ) + + quantity_value = UNSET + if quantity is not None: + quantity_value = quantity if isinstance(quantity, Quantity) else Quantity(quantity) + + response = _get_latest_circuit_transient_rating.sync_detailed( + client=client, + facility_id=facility_id, + x_region=x_region, + quantity=quantity_value, + since=UNSET if since is None else as_zulu(since), + ) + if response.status_code != 200: + status = int(response.status_code) + raise HeimdallApiError( + f"Error fetching latest circuit transient rating: {status} {response.status_code.phrase}" + f" - {body_preview(response.content)}", + status_code=status, + ) + return response.parsed + + def get_latest_circuit_rating_forecasts( client: AuthenticatedClient, facility_id: UUID, x_region: str ) -> CapacityMonitoringV1FacilitiesGetLatestCircuitRatingForecastsResponse200: diff --git a/python/heimdall_api_client/capacity_monitoring_api_client/api/facility/capacity_monitoring_v1_facilities_get_latest_circuit_transient_rating.py b/python/heimdall_api_client/capacity_monitoring_api_client/api/facility/capacity_monitoring_v1_facilities_get_latest_circuit_transient_rating.py new file mode 100644 index 0000000..51f2bb6 --- /dev/null +++ b/python/heimdall_api_client/capacity_monitoring_api_client/api/facility/capacity_monitoring_v1_facilities_get_latest_circuit_transient_rating.py @@ -0,0 +1,410 @@ +import datetime +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.capacity_monitoring_v1_facilities_get_latest_circuit_transient_rating_response_200 import ( + CapacityMonitoringV1FacilitiesGetLatestCircuitTransientRatingResponse200, +) +from ...models.capacity_monitoring_v1_facilities_get_latest_circuit_transient_rating_x_region import ( + CapacityMonitoringV1FacilitiesGetLatestCircuitTransientRatingXRegion, +) +from ...models.problem_details import ProblemDetails +from ...models.quantity import Quantity +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + facility_id: UUID, + *, + quantity: Quantity | Unset = UNSET, + since: datetime.datetime | Unset = UNSET, + x_region: CapacityMonitoringV1FacilitiesGetLatestCircuitTransientRatingXRegion + | Unset = CapacityMonitoringV1FacilitiesGetLatestCircuitTransientRatingXRegion.EU, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + if not isinstance(x_region, Unset): + headers["x-region"] = str(x_region) + + params: dict[str, Any] = {} + + json_quantity: str | Unset = UNSET + if not isinstance(quantity, Unset): + json_quantity = quantity.value + + params["quantity"] = json_quantity + + json_since: str | Unset = UNSET + if not isinstance(since, Unset): + json_since = since.isoformat() + params["since"] = json_since + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "get", + "url": "/capacity_monitoring/v1/facilities/{facility_id}/circuit_transient_ratings/latest".format( + facility_id=quote(str(facility_id), safe=""), + ), + "params": params, + } + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | CapacityMonitoringV1FacilitiesGetLatestCircuitTransientRatingResponse200 | ProblemDetails | None: + if response.status_code == 200: + response_200 = CapacityMonitoringV1FacilitiesGetLatestCircuitTransientRatingResponse200.from_dict( + response.json() + ) + + return response_200 + + if response.status_code == 400: + response_400 = ProblemDetails.from_dict(response.json()) + + return response_400 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = ProblemDetails.from_dict(response.json()) + + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if response.status_code == 500: + response_500 = ProblemDetails.from_dict(response.json()) + + return response_500 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | CapacityMonitoringV1FacilitiesGetLatestCircuitTransientRatingResponse200 | ProblemDetails]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + facility_id: UUID, + *, + client: AuthenticatedClient | Client, + quantity: Quantity | Unset = UNSET, + since: datetime.datetime | Unset = UNSET, + x_region: CapacityMonitoringV1FacilitiesGetLatestCircuitTransientRatingXRegion + | Unset = CapacityMonitoringV1FacilitiesGetLatestCircuitTransientRatingXRegion.EU, +) -> Response[Any | CapacityMonitoringV1FacilitiesGetLatestCircuitTransientRatingResponse200 | ProblemDetails]: + r"""Get latest circuit transient rating + + This endpoint returns the most recent circuit transient rating for the facility, including the + limiting facility component for each duration. + + The circuit transient rating is the line transient rating capped, per duration, by the most-limiting + facility component's emergency rating. It is the short-duration overload equivalent of the circuit + rating and can be used as a real-time emergency rating in operations. + + A transient rating is a set of per-duration values calculated at a single point in time. The + response + contains one `timestamp` and a `ratings` array with one entry per calculated duration (for example + 5, 10 or 15 minutes), and every calculated duration is returned. Transient ratings are calculated + for + the configured durations of one hour or shorter, so a configured duration longer than one hour is + not + calculated and is absent from the response. + + Note: If the limiting factor for a duration is not a specific facility component—such as when the + value + is constrained by the line transient rating itself—the limiting component id will be null. + + This endpoint returns real-time data and can be polled at short intervals (for example every 3–5 + minutes) for operational monitoring. + + ### Quantity + Use the optional `quantity` query parameter to choose the quantity returned: + - `current` (default) — circuit transient rating in amperes (`unit: \"Ampere\"`). + - `apparent_power` — circuit transient rating converted to three-phase apparent power in MVA + (`unit: \"MVA\"`) using `S = sqrt(3) * V * I / 1,000,000`. + + ### Voltage selection for `apparent_power` + The line's **operational voltage** is used when it is set and positive; otherwise the **nominal + voltage** is used. + Both voltages are exposed on the facility in the `GET /assets/v1/assets` response so clients can + verify which value the calculation would use. + If neither voltage is usable, the response is `404`. + + Args: + facility_id (UUID): + quantity (Quantity | Unset): Which quantity to return from a rating endpoint: + - `current` — value in amperes. + - `apparent_power` — value converted to MVA using `S = sqrt(3) * V * I / 1,000,000`. + since (datetime.datetime | Unset): Example: 2024-07-01 12:00:00.001000+00:00. + x_region (CapacityMonitoringV1FacilitiesGetLatestCircuitTransientRatingXRegion | Unset): + Default: CapacityMonitoringV1FacilitiesGetLatestCircuitTransientRatingXRegion.EU. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | CapacityMonitoringV1FacilitiesGetLatestCircuitTransientRatingResponse200 | ProblemDetails] + """ + + kwargs = _get_kwargs( + facility_id=facility_id, + quantity=quantity, + since=since, + x_region=x_region, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + facility_id: UUID, + *, + client: AuthenticatedClient | Client, + quantity: Quantity | Unset = UNSET, + since: datetime.datetime | Unset = UNSET, + x_region: CapacityMonitoringV1FacilitiesGetLatestCircuitTransientRatingXRegion + | Unset = CapacityMonitoringV1FacilitiesGetLatestCircuitTransientRatingXRegion.EU, +) -> Any | CapacityMonitoringV1FacilitiesGetLatestCircuitTransientRatingResponse200 | ProblemDetails | None: + r"""Get latest circuit transient rating + + This endpoint returns the most recent circuit transient rating for the facility, including the + limiting facility component for each duration. + + The circuit transient rating is the line transient rating capped, per duration, by the most-limiting + facility component's emergency rating. It is the short-duration overload equivalent of the circuit + rating and can be used as a real-time emergency rating in operations. + + A transient rating is a set of per-duration values calculated at a single point in time. The + response + contains one `timestamp` and a `ratings` array with one entry per calculated duration (for example + 5, 10 or 15 minutes), and every calculated duration is returned. Transient ratings are calculated + for + the configured durations of one hour or shorter, so a configured duration longer than one hour is + not + calculated and is absent from the response. + + Note: If the limiting factor for a duration is not a specific facility component—such as when the + value + is constrained by the line transient rating itself—the limiting component id will be null. + + This endpoint returns real-time data and can be polled at short intervals (for example every 3–5 + minutes) for operational monitoring. + + ### Quantity + Use the optional `quantity` query parameter to choose the quantity returned: + - `current` (default) — circuit transient rating in amperes (`unit: \"Ampere\"`). + - `apparent_power` — circuit transient rating converted to three-phase apparent power in MVA + (`unit: \"MVA\"`) using `S = sqrt(3) * V * I / 1,000,000`. + + ### Voltage selection for `apparent_power` + The line's **operational voltage** is used when it is set and positive; otherwise the **nominal + voltage** is used. + Both voltages are exposed on the facility in the `GET /assets/v1/assets` response so clients can + verify which value the calculation would use. + If neither voltage is usable, the response is `404`. + + Args: + facility_id (UUID): + quantity (Quantity | Unset): Which quantity to return from a rating endpoint: + - `current` — value in amperes. + - `apparent_power` — value converted to MVA using `S = sqrt(3) * V * I / 1,000,000`. + since (datetime.datetime | Unset): Example: 2024-07-01 12:00:00.001000+00:00. + x_region (CapacityMonitoringV1FacilitiesGetLatestCircuitTransientRatingXRegion | Unset): + Default: CapacityMonitoringV1FacilitiesGetLatestCircuitTransientRatingXRegion.EU. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | CapacityMonitoringV1FacilitiesGetLatestCircuitTransientRatingResponse200 | ProblemDetails + """ + + return sync_detailed( + facility_id=facility_id, + client=client, + quantity=quantity, + since=since, + x_region=x_region, + ).parsed + + +async def asyncio_detailed( + facility_id: UUID, + *, + client: AuthenticatedClient | Client, + quantity: Quantity | Unset = UNSET, + since: datetime.datetime | Unset = UNSET, + x_region: CapacityMonitoringV1FacilitiesGetLatestCircuitTransientRatingXRegion + | Unset = CapacityMonitoringV1FacilitiesGetLatestCircuitTransientRatingXRegion.EU, +) -> Response[Any | CapacityMonitoringV1FacilitiesGetLatestCircuitTransientRatingResponse200 | ProblemDetails]: + r"""Get latest circuit transient rating + + This endpoint returns the most recent circuit transient rating for the facility, including the + limiting facility component for each duration. + + The circuit transient rating is the line transient rating capped, per duration, by the most-limiting + facility component's emergency rating. It is the short-duration overload equivalent of the circuit + rating and can be used as a real-time emergency rating in operations. + + A transient rating is a set of per-duration values calculated at a single point in time. The + response + contains one `timestamp` and a `ratings` array with one entry per calculated duration (for example + 5, 10 or 15 minutes), and every calculated duration is returned. Transient ratings are calculated + for + the configured durations of one hour or shorter, so a configured duration longer than one hour is + not + calculated and is absent from the response. + + Note: If the limiting factor for a duration is not a specific facility component—such as when the + value + is constrained by the line transient rating itself—the limiting component id will be null. + + This endpoint returns real-time data and can be polled at short intervals (for example every 3–5 + minutes) for operational monitoring. + + ### Quantity + Use the optional `quantity` query parameter to choose the quantity returned: + - `current` (default) — circuit transient rating in amperes (`unit: \"Ampere\"`). + - `apparent_power` — circuit transient rating converted to three-phase apparent power in MVA + (`unit: \"MVA\"`) using `S = sqrt(3) * V * I / 1,000,000`. + + ### Voltage selection for `apparent_power` + The line's **operational voltage** is used when it is set and positive; otherwise the **nominal + voltage** is used. + Both voltages are exposed on the facility in the `GET /assets/v1/assets` response so clients can + verify which value the calculation would use. + If neither voltage is usable, the response is `404`. + + Args: + facility_id (UUID): + quantity (Quantity | Unset): Which quantity to return from a rating endpoint: + - `current` — value in amperes. + - `apparent_power` — value converted to MVA using `S = sqrt(3) * V * I / 1,000,000`. + since (datetime.datetime | Unset): Example: 2024-07-01 12:00:00.001000+00:00. + x_region (CapacityMonitoringV1FacilitiesGetLatestCircuitTransientRatingXRegion | Unset): + Default: CapacityMonitoringV1FacilitiesGetLatestCircuitTransientRatingXRegion.EU. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | CapacityMonitoringV1FacilitiesGetLatestCircuitTransientRatingResponse200 | ProblemDetails] + """ + + kwargs = _get_kwargs( + facility_id=facility_id, + quantity=quantity, + since=since, + x_region=x_region, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + facility_id: UUID, + *, + client: AuthenticatedClient | Client, + quantity: Quantity | Unset = UNSET, + since: datetime.datetime | Unset = UNSET, + x_region: CapacityMonitoringV1FacilitiesGetLatestCircuitTransientRatingXRegion + | Unset = CapacityMonitoringV1FacilitiesGetLatestCircuitTransientRatingXRegion.EU, +) -> Any | CapacityMonitoringV1FacilitiesGetLatestCircuitTransientRatingResponse200 | ProblemDetails | None: + r"""Get latest circuit transient rating + + This endpoint returns the most recent circuit transient rating for the facility, including the + limiting facility component for each duration. + + The circuit transient rating is the line transient rating capped, per duration, by the most-limiting + facility component's emergency rating. It is the short-duration overload equivalent of the circuit + rating and can be used as a real-time emergency rating in operations. + + A transient rating is a set of per-duration values calculated at a single point in time. The + response + contains one `timestamp` and a `ratings` array with one entry per calculated duration (for example + 5, 10 or 15 minutes), and every calculated duration is returned. Transient ratings are calculated + for + the configured durations of one hour or shorter, so a configured duration longer than one hour is + not + calculated and is absent from the response. + + Note: If the limiting factor for a duration is not a specific facility component—such as when the + value + is constrained by the line transient rating itself—the limiting component id will be null. + + This endpoint returns real-time data and can be polled at short intervals (for example every 3–5 + minutes) for operational monitoring. + + ### Quantity + Use the optional `quantity` query parameter to choose the quantity returned: + - `current` (default) — circuit transient rating in amperes (`unit: \"Ampere\"`). + - `apparent_power` — circuit transient rating converted to three-phase apparent power in MVA + (`unit: \"MVA\"`) using `S = sqrt(3) * V * I / 1,000,000`. + + ### Voltage selection for `apparent_power` + The line's **operational voltage** is used when it is set and positive; otherwise the **nominal + voltage** is used. + Both voltages are exposed on the facility in the `GET /assets/v1/assets` response so clients can + verify which value the calculation would use. + If neither voltage is usable, the response is `404`. + + Args: + facility_id (UUID): + quantity (Quantity | Unset): Which quantity to return from a rating endpoint: + - `current` — value in amperes. + - `apparent_power` — value converted to MVA using `S = sqrt(3) * V * I / 1,000,000`. + since (datetime.datetime | Unset): Example: 2024-07-01 12:00:00.001000+00:00. + x_region (CapacityMonitoringV1FacilitiesGetLatestCircuitTransientRatingXRegion | Unset): + Default: CapacityMonitoringV1FacilitiesGetLatestCircuitTransientRatingXRegion.EU. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | CapacityMonitoringV1FacilitiesGetLatestCircuitTransientRatingResponse200 | ProblemDetails + """ + + return ( + await asyncio_detailed( + facility_id=facility_id, + client=client, + quantity=quantity, + since=since, + x_region=x_region, + ) + ).parsed diff --git a/python/heimdall_api_client/capacity_monitoring_api_client/api/line/capacity_monitoring_v1_lines_get_latest_transient_rating.py b/python/heimdall_api_client/capacity_monitoring_api_client/api/line/capacity_monitoring_v1_lines_get_latest_transient_rating.py new file mode 100644 index 0000000..6dc5d13 --- /dev/null +++ b/python/heimdall_api_client/capacity_monitoring_api_client/api/line/capacity_monitoring_v1_lines_get_latest_transient_rating.py @@ -0,0 +1,376 @@ +import datetime +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.capacity_monitoring_v1_lines_get_latest_transient_rating_response_200 import ( + CapacityMonitoringV1LinesGetLatestTransientRatingResponse200, +) +from ...models.capacity_monitoring_v1_lines_get_latest_transient_rating_x_region import ( + CapacityMonitoringV1LinesGetLatestTransientRatingXRegion, +) +from ...models.problem_details import ProblemDetails +from ...models.quantity import Quantity +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + line_id: UUID, + *, + quantity: Quantity | Unset = UNSET, + since: datetime.datetime | Unset = UNSET, + x_region: CapacityMonitoringV1LinesGetLatestTransientRatingXRegion + | Unset = CapacityMonitoringV1LinesGetLatestTransientRatingXRegion.EU, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + if not isinstance(x_region, Unset): + headers["x-region"] = str(x_region) + + params: dict[str, Any] = {} + + json_quantity: str | Unset = UNSET + if not isinstance(quantity, Unset): + json_quantity = quantity.value + + params["quantity"] = json_quantity + + json_since: str | Unset = UNSET + if not isinstance(since, Unset): + json_since = since.isoformat() + params["since"] = json_since + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "get", + "url": "/capacity_monitoring/v1/lines/{line_id}/transient_ratings/latest".format( + line_id=quote(str(line_id), safe=""), + ), + "params": params, + } + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | CapacityMonitoringV1LinesGetLatestTransientRatingResponse200 | ProblemDetails | None: + if response.status_code == 200: + response_200 = CapacityMonitoringV1LinesGetLatestTransientRatingResponse200.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = ProblemDetails.from_dict(response.json()) + + return response_400 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = ProblemDetails.from_dict(response.json()) + + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if response.status_code == 500: + response_500 = ProblemDetails.from_dict(response.json()) + + return response_500 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | CapacityMonitoringV1LinesGetLatestTransientRatingResponse200 | ProblemDetails]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + line_id: UUID, + *, + client: AuthenticatedClient | Client, + quantity: Quantity | Unset = UNSET, + since: datetime.datetime | Unset = UNSET, + x_region: CapacityMonitoringV1LinesGetLatestTransientRatingXRegion + | Unset = CapacityMonitoringV1LinesGetLatestTransientRatingXRegion.EU, +) -> Response[Any | CapacityMonitoringV1LinesGetLatestTransientRatingResponse200 | ProblemDetails]: + r"""Get latest line transient rating + + This endpoint returns the most recent line transient rating for the line: the short-duration + overload ampacity the line can sustain for each calculated duration. + + A transient rating is a set of per-duration values calculated at a single point in time. The + response + contains one `timestamp` and a `ratings` array with one entry per calculated duration (for example + 5, 10 or 15 minutes), and every calculated duration is returned. Transient ratings are calculated + for + the configured durations of one hour or shorter, so a configured duration longer than one hour is + not + calculated and is absent from the response. + + This endpoint returns real-time data and can be polled at short intervals (for example every 3–5 + minutes) for operational monitoring. + + ### Quantity + Use the optional `quantity` query parameter to choose the quantity returned: + - `current` (default) — line transient rating in amperes (`unit: \"Ampere\"`). + - `apparent_power` — line transient rating converted to three-phase apparent power in MVA (`unit: + \"MVA\"`) using `S = sqrt(3) * V * I / 1,000,000`. + + ### Voltage selection for `apparent_power` + The line's **operational voltage** is used when it is set and positive; otherwise the **nominal + voltage** is used. + Both voltages are exposed on the facility in the `GET /assets/v1/assets` response so clients can + verify which value the calculation would use. + If neither voltage is usable, the response is `404`. + + Args: + line_id (UUID): + quantity (Quantity | Unset): Which quantity to return from a rating endpoint: + - `current` — value in amperes. + - `apparent_power` — value converted to MVA using `S = sqrt(3) * V * I / 1,000,000`. + since (datetime.datetime | Unset): Example: 2024-07-01 12:00:00.001000+00:00. + x_region (CapacityMonitoringV1LinesGetLatestTransientRatingXRegion | Unset): Default: + CapacityMonitoringV1LinesGetLatestTransientRatingXRegion.EU. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | CapacityMonitoringV1LinesGetLatestTransientRatingResponse200 | ProblemDetails] + """ + + kwargs = _get_kwargs( + line_id=line_id, + quantity=quantity, + since=since, + x_region=x_region, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + line_id: UUID, + *, + client: AuthenticatedClient | Client, + quantity: Quantity | Unset = UNSET, + since: datetime.datetime | Unset = UNSET, + x_region: CapacityMonitoringV1LinesGetLatestTransientRatingXRegion + | Unset = CapacityMonitoringV1LinesGetLatestTransientRatingXRegion.EU, +) -> Any | CapacityMonitoringV1LinesGetLatestTransientRatingResponse200 | ProblemDetails | None: + r"""Get latest line transient rating + + This endpoint returns the most recent line transient rating for the line: the short-duration + overload ampacity the line can sustain for each calculated duration. + + A transient rating is a set of per-duration values calculated at a single point in time. The + response + contains one `timestamp` and a `ratings` array with one entry per calculated duration (for example + 5, 10 or 15 minutes), and every calculated duration is returned. Transient ratings are calculated + for + the configured durations of one hour or shorter, so a configured duration longer than one hour is + not + calculated and is absent from the response. + + This endpoint returns real-time data and can be polled at short intervals (for example every 3–5 + minutes) for operational monitoring. + + ### Quantity + Use the optional `quantity` query parameter to choose the quantity returned: + - `current` (default) — line transient rating in amperes (`unit: \"Ampere\"`). + - `apparent_power` — line transient rating converted to three-phase apparent power in MVA (`unit: + \"MVA\"`) using `S = sqrt(3) * V * I / 1,000,000`. + + ### Voltage selection for `apparent_power` + The line's **operational voltage** is used when it is set and positive; otherwise the **nominal + voltage** is used. + Both voltages are exposed on the facility in the `GET /assets/v1/assets` response so clients can + verify which value the calculation would use. + If neither voltage is usable, the response is `404`. + + Args: + line_id (UUID): + quantity (Quantity | Unset): Which quantity to return from a rating endpoint: + - `current` — value in amperes. + - `apparent_power` — value converted to MVA using `S = sqrt(3) * V * I / 1,000,000`. + since (datetime.datetime | Unset): Example: 2024-07-01 12:00:00.001000+00:00. + x_region (CapacityMonitoringV1LinesGetLatestTransientRatingXRegion | Unset): Default: + CapacityMonitoringV1LinesGetLatestTransientRatingXRegion.EU. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | CapacityMonitoringV1LinesGetLatestTransientRatingResponse200 | ProblemDetails + """ + + return sync_detailed( + line_id=line_id, + client=client, + quantity=quantity, + since=since, + x_region=x_region, + ).parsed + + +async def asyncio_detailed( + line_id: UUID, + *, + client: AuthenticatedClient | Client, + quantity: Quantity | Unset = UNSET, + since: datetime.datetime | Unset = UNSET, + x_region: CapacityMonitoringV1LinesGetLatestTransientRatingXRegion + | Unset = CapacityMonitoringV1LinesGetLatestTransientRatingXRegion.EU, +) -> Response[Any | CapacityMonitoringV1LinesGetLatestTransientRatingResponse200 | ProblemDetails]: + r"""Get latest line transient rating + + This endpoint returns the most recent line transient rating for the line: the short-duration + overload ampacity the line can sustain for each calculated duration. + + A transient rating is a set of per-duration values calculated at a single point in time. The + response + contains one `timestamp` and a `ratings` array with one entry per calculated duration (for example + 5, 10 or 15 minutes), and every calculated duration is returned. Transient ratings are calculated + for + the configured durations of one hour or shorter, so a configured duration longer than one hour is + not + calculated and is absent from the response. + + This endpoint returns real-time data and can be polled at short intervals (for example every 3–5 + minutes) for operational monitoring. + + ### Quantity + Use the optional `quantity` query parameter to choose the quantity returned: + - `current` (default) — line transient rating in amperes (`unit: \"Ampere\"`). + - `apparent_power` — line transient rating converted to three-phase apparent power in MVA (`unit: + \"MVA\"`) using `S = sqrt(3) * V * I / 1,000,000`. + + ### Voltage selection for `apparent_power` + The line's **operational voltage** is used when it is set and positive; otherwise the **nominal + voltage** is used. + Both voltages are exposed on the facility in the `GET /assets/v1/assets` response so clients can + verify which value the calculation would use. + If neither voltage is usable, the response is `404`. + + Args: + line_id (UUID): + quantity (Quantity | Unset): Which quantity to return from a rating endpoint: + - `current` — value in amperes. + - `apparent_power` — value converted to MVA using `S = sqrt(3) * V * I / 1,000,000`. + since (datetime.datetime | Unset): Example: 2024-07-01 12:00:00.001000+00:00. + x_region (CapacityMonitoringV1LinesGetLatestTransientRatingXRegion | Unset): Default: + CapacityMonitoringV1LinesGetLatestTransientRatingXRegion.EU. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | CapacityMonitoringV1LinesGetLatestTransientRatingResponse200 | ProblemDetails] + """ + + kwargs = _get_kwargs( + line_id=line_id, + quantity=quantity, + since=since, + x_region=x_region, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + line_id: UUID, + *, + client: AuthenticatedClient | Client, + quantity: Quantity | Unset = UNSET, + since: datetime.datetime | Unset = UNSET, + x_region: CapacityMonitoringV1LinesGetLatestTransientRatingXRegion + | Unset = CapacityMonitoringV1LinesGetLatestTransientRatingXRegion.EU, +) -> Any | CapacityMonitoringV1LinesGetLatestTransientRatingResponse200 | ProblemDetails | None: + r"""Get latest line transient rating + + This endpoint returns the most recent line transient rating for the line: the short-duration + overload ampacity the line can sustain for each calculated duration. + + A transient rating is a set of per-duration values calculated at a single point in time. The + response + contains one `timestamp` and a `ratings` array with one entry per calculated duration (for example + 5, 10 or 15 minutes), and every calculated duration is returned. Transient ratings are calculated + for + the configured durations of one hour or shorter, so a configured duration longer than one hour is + not + calculated and is absent from the response. + + This endpoint returns real-time data and can be polled at short intervals (for example every 3–5 + minutes) for operational monitoring. + + ### Quantity + Use the optional `quantity` query parameter to choose the quantity returned: + - `current` (default) — line transient rating in amperes (`unit: \"Ampere\"`). + - `apparent_power` — line transient rating converted to three-phase apparent power in MVA (`unit: + \"MVA\"`) using `S = sqrt(3) * V * I / 1,000,000`. + + ### Voltage selection for `apparent_power` + The line's **operational voltage** is used when it is set and positive; otherwise the **nominal + voltage** is used. + Both voltages are exposed on the facility in the `GET /assets/v1/assets` response so clients can + verify which value the calculation would use. + If neither voltage is usable, the response is `404`. + + Args: + line_id (UUID): + quantity (Quantity | Unset): Which quantity to return from a rating endpoint: + - `current` — value in amperes. + - `apparent_power` — value converted to MVA using `S = sqrt(3) * V * I / 1,000,000`. + since (datetime.datetime | Unset): Example: 2024-07-01 12:00:00.001000+00:00. + x_region (CapacityMonitoringV1LinesGetLatestTransientRatingXRegion | Unset): Default: + CapacityMonitoringV1LinesGetLatestTransientRatingXRegion.EU. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | CapacityMonitoringV1LinesGetLatestTransientRatingResponse200 | ProblemDetails + """ + + return ( + await asyncio_detailed( + line_id=line_id, + client=client, + quantity=quantity, + since=since, + x_region=x_region, + ) + ).parsed diff --git a/python/heimdall_api_client/capacity_monitoring_api_client/models/__init__.py b/python/heimdall_api_client/capacity_monitoring_api_client/models/__init__.py index c57d335..e5c6651 100644 --- a/python/heimdall_api_client/capacity_monitoring_api_client/models/__init__.py +++ b/python/heimdall_api_client/capacity_monitoring_api_client/models/__init__.py @@ -19,6 +19,12 @@ from .capacity_monitoring_v1_facilities_get_latest_circuit_rating_x_region import ( CapacityMonitoringV1FacilitiesGetLatestCircuitRatingXRegion, ) +from .capacity_monitoring_v1_facilities_get_latest_circuit_transient_rating_response_200 import ( + CapacityMonitoringV1FacilitiesGetLatestCircuitTransientRatingResponse200, +) +from .capacity_monitoring_v1_facilities_get_latest_circuit_transient_rating_x_region import ( + CapacityMonitoringV1FacilitiesGetLatestCircuitTransientRatingXRegion, +) from .capacity_monitoring_v1_lines_get_heimdall_aars_response_200 import ( CapacityMonitoringV1LinesGetHeimdallAarsResponse200, ) @@ -51,9 +57,17 @@ from .capacity_monitoring_v1_lines_get_latest_heimdall_dlr_x_region import ( CapacityMonitoringV1LinesGetLatestHeimdallDlrXRegion, ) +from .capacity_monitoring_v1_lines_get_latest_transient_rating_response_200 import ( + CapacityMonitoringV1LinesGetLatestTransientRatingResponse200, +) +from .capacity_monitoring_v1_lines_get_latest_transient_rating_x_region import ( + CapacityMonitoringV1LinesGetLatestTransientRatingXRegion, +) from .circuit_rating import CircuitRating from .circuit_rating_forecasts import CircuitRatingForecasts from .circuit_ratings import CircuitRatings +from .circuit_transient_rating import CircuitTransientRating +from .circuit_transient_rating_value import CircuitTransientRatingValue from .heimdall_aar import HeimdallAar from .heimdall_aar_forecasts import HeimdallAarForecasts from .heimdall_aars import HeimdallAars @@ -61,8 +75,12 @@ from .heimdall_dlr_forecasts import HeimdallDlrForecasts from .heimdall_dlrs import HeimdallDlrs from .latest_circuit_rating import LatestCircuitRating +from .latest_circuit_transient_rating import LatestCircuitTransientRating from .latest_heimdall_aar import LatestHeimdallAar from .latest_heimdall_dlr import LatestHeimdallDlr +from .latest_line_transient_rating import LatestLineTransientRating +from .line_transient_rating import LineTransientRating +from .line_transient_rating_value import LineTransientRatingValue from .predicted_circuit_rating_forecast import PredictedCircuitRatingForecast from .predicted_forecast import PredictedForecast from .probabilistic_circuit_rating_ampacity import ProbabilisticCircuitRatingAmpacity @@ -78,6 +96,8 @@ "CapacityMonitoringV1FacilitiesGetLatestCircuitRatingForecastsXRegion", "CapacityMonitoringV1FacilitiesGetLatestCircuitRatingResponse200", "CapacityMonitoringV1FacilitiesGetLatestCircuitRatingXRegion", + "CapacityMonitoringV1FacilitiesGetLatestCircuitTransientRatingResponse200", + "CapacityMonitoringV1FacilitiesGetLatestCircuitTransientRatingXRegion", "CapacityMonitoringV1LinesGetHeimdallAarsResponse200", "CapacityMonitoringV1LinesGetHeimdallAarsXRegion", "CapacityMonitoringV1LinesGetHeimdallDlrsResponse200", @@ -90,9 +110,13 @@ "CapacityMonitoringV1LinesGetLatestHeimdallDlrForecastsXRegion", "CapacityMonitoringV1LinesGetLatestHeimdallDlrResponse200", "CapacityMonitoringV1LinesGetLatestHeimdallDlrXRegion", + "CapacityMonitoringV1LinesGetLatestTransientRatingResponse200", + "CapacityMonitoringV1LinesGetLatestTransientRatingXRegion", "CircuitRating", "CircuitRatingForecasts", "CircuitRatings", + "CircuitTransientRating", + "CircuitTransientRatingValue", "HeimdallAar", "HeimdallAarForecasts", "HeimdallAars", @@ -100,8 +124,12 @@ "HeimdallDlrForecasts", "HeimdallDlrs", "LatestCircuitRating", + "LatestCircuitTransientRating", "LatestHeimdallAar", "LatestHeimdallDlr", + "LatestLineTransientRating", + "LineTransientRating", + "LineTransientRatingValue", "PredictedCircuitRatingForecast", "PredictedForecast", "ProbabilisticCircuitRatingAmpacity", diff --git a/python/heimdall_api_client/capacity_monitoring_api_client/models/capacity_monitoring_v1_facilities_get_latest_circuit_transient_rating_response_200.py b/python/heimdall_api_client/capacity_monitoring_api_client/models/capacity_monitoring_v1_facilities_get_latest_circuit_transient_rating_response_200.py new file mode 100644 index 0000000..4e1a01e --- /dev/null +++ b/python/heimdall_api_client/capacity_monitoring_api_client/models/capacity_monitoring_v1_facilities_get_latest_circuit_transient_rating_response_200.py @@ -0,0 +1,67 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.latest_circuit_transient_rating import LatestCircuitTransientRating + + +T = TypeVar("T", bound="CapacityMonitoringV1FacilitiesGetLatestCircuitTransientRatingResponse200") + + +@_attrs_define +class CapacityMonitoringV1FacilitiesGetLatestCircuitTransientRatingResponse200: + """ + Attributes: + data (LatestCircuitTransientRating): + """ + + data: LatestCircuitTransientRating + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + data = self.data.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "data": data, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.latest_circuit_transient_rating import LatestCircuitTransientRating + + d = dict(src_dict) + data = LatestCircuitTransientRating.from_dict(d.pop("data")) + + capacity_monitoring_v1_facilities_get_latest_circuit_transient_rating_response_200 = cls( + data=data, + ) + + capacity_monitoring_v1_facilities_get_latest_circuit_transient_rating_response_200.additional_properties = d + return capacity_monitoring_v1_facilities_get_latest_circuit_transient_rating_response_200 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/python/heimdall_api_client/capacity_monitoring_api_client/models/capacity_monitoring_v1_facilities_get_latest_circuit_transient_rating_x_region.py b/python/heimdall_api_client/capacity_monitoring_api_client/models/capacity_monitoring_v1_facilities_get_latest_circuit_transient_rating_x_region.py new file mode 100644 index 0000000..626b3e8 --- /dev/null +++ b/python/heimdall_api_client/capacity_monitoring_api_client/models/capacity_monitoring_v1_facilities_get_latest_circuit_transient_rating_x_region.py @@ -0,0 +1,9 @@ +from enum import Enum + + +class CapacityMonitoringV1FacilitiesGetLatestCircuitTransientRatingXRegion(str, Enum): + EU = "eu" + US = "us" + + def __str__(self) -> str: + return str(self.value) diff --git a/python/heimdall_api_client/capacity_monitoring_api_client/models/capacity_monitoring_v1_lines_get_latest_transient_rating_response_200.py b/python/heimdall_api_client/capacity_monitoring_api_client/models/capacity_monitoring_v1_lines_get_latest_transient_rating_response_200.py new file mode 100644 index 0000000..5e57f0a --- /dev/null +++ b/python/heimdall_api_client/capacity_monitoring_api_client/models/capacity_monitoring_v1_lines_get_latest_transient_rating_response_200.py @@ -0,0 +1,67 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.latest_line_transient_rating import LatestLineTransientRating + + +T = TypeVar("T", bound="CapacityMonitoringV1LinesGetLatestTransientRatingResponse200") + + +@_attrs_define +class CapacityMonitoringV1LinesGetLatestTransientRatingResponse200: + """ + Attributes: + data (LatestLineTransientRating): + """ + + data: LatestLineTransientRating + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + data = self.data.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "data": data, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.latest_line_transient_rating import LatestLineTransientRating + + d = dict(src_dict) + data = LatestLineTransientRating.from_dict(d.pop("data")) + + capacity_monitoring_v1_lines_get_latest_transient_rating_response_200 = cls( + data=data, + ) + + capacity_monitoring_v1_lines_get_latest_transient_rating_response_200.additional_properties = d + return capacity_monitoring_v1_lines_get_latest_transient_rating_response_200 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/python/heimdall_api_client/capacity_monitoring_api_client/models/capacity_monitoring_v1_lines_get_latest_transient_rating_x_region.py b/python/heimdall_api_client/capacity_monitoring_api_client/models/capacity_monitoring_v1_lines_get_latest_transient_rating_x_region.py new file mode 100644 index 0000000..5ab5adc --- /dev/null +++ b/python/heimdall_api_client/capacity_monitoring_api_client/models/capacity_monitoring_v1_lines_get_latest_transient_rating_x_region.py @@ -0,0 +1,9 @@ +from enum import Enum + + +class CapacityMonitoringV1LinesGetLatestTransientRatingXRegion(str, Enum): + EU = "eu" + US = "us" + + def __str__(self) -> str: + return str(self.value) diff --git a/python/heimdall_api_client/capacity_monitoring_api_client/models/circuit_transient_rating.py b/python/heimdall_api_client/capacity_monitoring_api_client/models/circuit_transient_rating.py new file mode 100644 index 0000000..8c521f7 --- /dev/null +++ b/python/heimdall_api_client/capacity_monitoring_api_client/models/circuit_transient_rating.py @@ -0,0 +1,87 @@ +from __future__ import annotations + +import datetime +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field +from dateutil.parser import isoparse + +if TYPE_CHECKING: + from ..models.circuit_transient_rating_value import CircuitTransientRatingValue + + +T = TypeVar("T", bound="CircuitTransientRating") + + +@_attrs_define +class CircuitTransientRating: + """ + Attributes: + timestamp (datetime.datetime): Time (in UTC) when the circuit transient rating was calculated. Example: + 2024-07-01 12:00:00.001000+00:00. + ratings (list[CircuitTransientRatingValue]): The circuit transient rating for each configured duration at the + given timestamp. Ordered by `duration_minutes` ascending. + """ + + timestamp: datetime.datetime + ratings: list[CircuitTransientRatingValue] + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + timestamp = self.timestamp.isoformat() + + ratings = [] + for ratings_item_data in self.ratings: + ratings_item = ratings_item_data.to_dict() + ratings.append(ratings_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "timestamp": timestamp, + "ratings": ratings, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.circuit_transient_rating_value import CircuitTransientRatingValue + + d = dict(src_dict) + timestamp = isoparse(d.pop("timestamp")) + + ratings = [] + _ratings = d.pop("ratings") + for ratings_item_data in _ratings: + ratings_item = CircuitTransientRatingValue.from_dict(ratings_item_data) + + ratings.append(ratings_item) + + circuit_transient_rating = cls( + timestamp=timestamp, + ratings=ratings, + ) + + circuit_transient_rating.additional_properties = d + return circuit_transient_rating + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/python/heimdall_api_client/capacity_monitoring_api_client/models/circuit_transient_rating_value.py b/python/heimdall_api_client/capacity_monitoring_api_client/models/circuit_transient_rating_value.py new file mode 100644 index 0000000..bcb545a --- /dev/null +++ b/python/heimdall_api_client/capacity_monitoring_api_client/models/circuit_transient_rating_value.py @@ -0,0 +1,109 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar, cast +from uuid import UUID + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="CircuitTransientRatingValue") + + +@_attrs_define +class CircuitTransientRatingValue: + """ + Attributes: + duration_minutes (int): The transient rating duration in minutes (for example 5, 10 or 15). Transient ratings + are not calculated for durations longer than one hour. Example: 10. + value (float): The circuit transient rating value for this duration at the given timestamp. The unit of this + value is given by the sibling `unit` field on the response: + - When `quantity=current` (default) → amperes. + - When `quantity=apparent_power` → MVA. + Example: 590.2. + limiting_component_id (None | Unset | UUID): Identifier of the facility component that caps the circuit + transient rating for this duration. When null, the value is not limited by a facility component (the line + transient rating is the binding constraint). Example: 00000000-0000-0000-0000-000000000000. + """ + + duration_minutes: int + value: float + limiting_component_id: None | Unset | UUID = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + duration_minutes = self.duration_minutes + + value = self.value + + limiting_component_id: None | str | Unset + if isinstance(self.limiting_component_id, Unset): + limiting_component_id = UNSET + elif isinstance(self.limiting_component_id, UUID): + limiting_component_id = str(self.limiting_component_id) + else: + limiting_component_id = self.limiting_component_id + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "duration_minutes": duration_minutes, + "value": value, + } + ) + if limiting_component_id is not UNSET: + field_dict["limiting_component_id"] = limiting_component_id + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + duration_minutes = d.pop("duration_minutes") + + value = d.pop("value") + + def _parse_limiting_component_id(data: object) -> None | Unset | UUID: + if data is None: + return data + if isinstance(data, Unset): + return data + try: + if not isinstance(data, str): + raise TypeError() + limiting_component_id_type_0 = UUID(data) + + return limiting_component_id_type_0 + except (TypeError, ValueError, AttributeError, KeyError): + pass + return cast(None | Unset | UUID, data) + + limiting_component_id = _parse_limiting_component_id(d.pop("limiting_component_id", UNSET)) + + circuit_transient_rating_value = cls( + duration_minutes=duration_minutes, + value=value, + limiting_component_id=limiting_component_id, + ) + + circuit_transient_rating_value.additional_properties = d + return circuit_transient_rating_value + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/python/heimdall_api_client/capacity_monitoring_api_client/models/latest_circuit_transient_rating.py b/python/heimdall_api_client/capacity_monitoring_api_client/models/latest_circuit_transient_rating.py new file mode 100644 index 0000000..053a467 --- /dev/null +++ b/python/heimdall_api_client/capacity_monitoring_api_client/models/latest_circuit_transient_rating.py @@ -0,0 +1,87 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.circuit_transient_rating import CircuitTransientRating + + +T = TypeVar("T", bound="LatestCircuitTransientRating") + + +@_attrs_define +class LatestCircuitTransientRating: + """ + Attributes: + metric (str): A human-readable label identifying the rating returned by this endpoint, independent of the + `quantity` query parameter. Example: Circuit transient rating. + unit (str): The unit of the values in the response. Depends on the requested `quantity` query parameter: + - `current` (default) → `"Ampere"` + - `apparent_power` → `"MVA"` + Example: Ampere. + circuit_transient_rating (CircuitTransientRating): + """ + + metric: str + unit: str + circuit_transient_rating: CircuitTransientRating + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + metric = self.metric + + unit = self.unit + + circuit_transient_rating = self.circuit_transient_rating.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "metric": metric, + "unit": unit, + "circuit_transient_rating": circuit_transient_rating, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.circuit_transient_rating import CircuitTransientRating + + d = dict(src_dict) + metric = d.pop("metric") + + unit = d.pop("unit") + + circuit_transient_rating = CircuitTransientRating.from_dict(d.pop("circuit_transient_rating")) + + latest_circuit_transient_rating = cls( + metric=metric, + unit=unit, + circuit_transient_rating=circuit_transient_rating, + ) + + latest_circuit_transient_rating.additional_properties = d + return latest_circuit_transient_rating + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/python/heimdall_api_client/capacity_monitoring_api_client/models/latest_line_transient_rating.py b/python/heimdall_api_client/capacity_monitoring_api_client/models/latest_line_transient_rating.py new file mode 100644 index 0000000..73673cd --- /dev/null +++ b/python/heimdall_api_client/capacity_monitoring_api_client/models/latest_line_transient_rating.py @@ -0,0 +1,87 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.line_transient_rating import LineTransientRating + + +T = TypeVar("T", bound="LatestLineTransientRating") + + +@_attrs_define +class LatestLineTransientRating: + """ + Attributes: + metric (str): A human-readable label identifying the rating returned by this endpoint, independent of the + `quantity` query parameter. Example: Line transient rating. + unit (str): The unit of the values in the response. Depends on the requested `quantity` query parameter: + - `current` (default) → `"Ampere"` + - `apparent_power` → `"MVA"` + Example: Ampere. + line_transient_rating (LineTransientRating): + """ + + metric: str + unit: str + line_transient_rating: LineTransientRating + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + metric = self.metric + + unit = self.unit + + line_transient_rating = self.line_transient_rating.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "metric": metric, + "unit": unit, + "line_transient_rating": line_transient_rating, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.line_transient_rating import LineTransientRating + + d = dict(src_dict) + metric = d.pop("metric") + + unit = d.pop("unit") + + line_transient_rating = LineTransientRating.from_dict(d.pop("line_transient_rating")) + + latest_line_transient_rating = cls( + metric=metric, + unit=unit, + line_transient_rating=line_transient_rating, + ) + + latest_line_transient_rating.additional_properties = d + return latest_line_transient_rating + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/python/heimdall_api_client/capacity_monitoring_api_client/models/line_transient_rating.py b/python/heimdall_api_client/capacity_monitoring_api_client/models/line_transient_rating.py new file mode 100644 index 0000000..982d0c8 --- /dev/null +++ b/python/heimdall_api_client/capacity_monitoring_api_client/models/line_transient_rating.py @@ -0,0 +1,87 @@ +from __future__ import annotations + +import datetime +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field +from dateutil.parser import isoparse + +if TYPE_CHECKING: + from ..models.line_transient_rating_value import LineTransientRatingValue + + +T = TypeVar("T", bound="LineTransientRating") + + +@_attrs_define +class LineTransientRating: + """ + Attributes: + timestamp (datetime.datetime): Time (in UTC) when the line transient rating was calculated. Example: 2024-07-01 + 12:00:00.001000+00:00. + ratings (list[LineTransientRatingValue]): The line transient rating for each configured duration at the given + timestamp. Ordered by `duration_minutes` ascending. + """ + + timestamp: datetime.datetime + ratings: list[LineTransientRatingValue] + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + timestamp = self.timestamp.isoformat() + + ratings = [] + for ratings_item_data in self.ratings: + ratings_item = ratings_item_data.to_dict() + ratings.append(ratings_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "timestamp": timestamp, + "ratings": ratings, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.line_transient_rating_value import LineTransientRatingValue + + d = dict(src_dict) + timestamp = isoparse(d.pop("timestamp")) + + ratings = [] + _ratings = d.pop("ratings") + for ratings_item_data in _ratings: + ratings_item = LineTransientRatingValue.from_dict(ratings_item_data) + + ratings.append(ratings_item) + + line_transient_rating = cls( + timestamp=timestamp, + ratings=ratings, + ) + + line_transient_rating.additional_properties = d + return line_transient_rating + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/python/heimdall_api_client/capacity_monitoring_api_client/models/line_transient_rating_value.py b/python/heimdall_api_client/capacity_monitoring_api_client/models/line_transient_rating_value.py new file mode 100644 index 0000000..5e06e53 --- /dev/null +++ b/python/heimdall_api_client/capacity_monitoring_api_client/models/line_transient_rating_value.py @@ -0,0 +1,74 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="LineTransientRatingValue") + + +@_attrs_define +class LineTransientRatingValue: + """ + Attributes: + duration_minutes (int): The transient rating duration in minutes (for example 5, 10 or 15). Transient ratings + are not calculated for durations longer than one hour. Example: 10. + value (float): The line transient rating value for this duration at the given timestamp. The unit of this value + is given by the sibling `unit` field on the response: + - When `quantity=current` (default) → amperes. + - When `quantity=apparent_power` → MVA. + Example: 620.5. + """ + + duration_minutes: int + value: float + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + duration_minutes = self.duration_minutes + + value = self.value + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "duration_minutes": duration_minutes, + "value": value, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + duration_minutes = d.pop("duration_minutes") + + value = d.pop("value") + + line_transient_rating_value = cls( + duration_minutes=duration_minutes, + value=value, + ) + + line_transient_rating_value.additional_properties = d + return line_transient_rating_value + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/python/heimdall_api_client/client.py b/python/heimdall_api_client/client.py index 365b9c6..185d3a6 100644 --- a/python/heimdall_api_client/client.py +++ b/python/heimdall_api_client/client.py @@ -21,6 +21,7 @@ get_latest_heimdall_arr_forecasts, get_latest_heimdall_dlr, get_latest_heimdall_dlr_forecasts, + get_latest_line_transient_rating, ) from heimdall_api_client.capacity_monitoring_api_client.models.quantity import Quantity from heimdall_api_client.errors import HeimdallApiError @@ -41,6 +42,9 @@ from heimdall_api_client.capacity_monitoring_api_client.models.capacity_monitoring_v1_facilities_get_latest_circuit_rating_response_200 import ( # noqa: E501 CapacityMonitoringV1FacilitiesGetLatestCircuitRatingResponse200, ) + from heimdall_api_client.capacity_monitoring_api_client.models.capacity_monitoring_v1_facilities_get_latest_circuit_transient_rating_response_200 import ( # noqa: E501 + CapacityMonitoringV1FacilitiesGetLatestCircuitTransientRatingResponse200, + ) from heimdall_api_client.capacity_monitoring_api_client.models.capacity_monitoring_v1_lines_get_heimdall_aars_response_200 import ( # noqa: E501 CapacityMonitoringV1LinesGetHeimdallAarsResponse200, ) @@ -59,6 +63,9 @@ from heimdall_api_client.capacity_monitoring_api_client.models.capacity_monitoring_v1_lines_get_latest_heimdall_dlr_response_200 import ( # noqa: E501 CapacityMonitoringV1LinesGetLatestHeimdallDlrResponse200, ) + from heimdall_api_client.capacity_monitoring_api_client.models.capacity_monitoring_v1_lines_get_latest_transient_rating_response_200 import ( # noqa: E501 + CapacityMonitoringV1LinesGetLatestTransientRatingResponse200, + ) from heimdall_api_client.grid_insights_api_client.models.grid_insights_v1_lines_get_apparent_power_response_200 import ( # noqa: E501 GridInsightsV1LinesGetApparentPowerResponse200, ) @@ -271,6 +278,29 @@ def get_latest_heimdall_aar( ) ) + def get_latest_line_transient_rating( + self, + line_id: UUID, + quantity: Quantity | str | None = None, + since: datetime.datetime | None = None, + ) -> CapacityMonitoringV1LinesGetLatestTransientRatingResponse200: + """ + Returns the latest line transient rating for a given line: the short-duration + overload ampacity the line can sustain for each calculated duration. + + The response holds one timestamp and one value per calculated duration. + `since` bounds how old the returned value may be. + """ + return self._execute_with_retry( + lambda: get_latest_line_transient_rating( + client=self._get_authenticated_client(), + line_id=line_id, + region=self._get_region(), + quantity=quantity, + since=since, + ) + ) + def get_latest_heimdall_dlr_forecasts( self, line_id: UUID ) -> CapacityMonitoringV1LinesGetLatestHeimdallDlrForecastsResponse200: @@ -314,6 +344,32 @@ def get_latest_circuit_rating( ) ) + def get_latest_circuit_transient_rating( + self, + facility_id: UUID, + quantity: Quantity | str | None = None, + since: datetime.datetime | None = None, + ) -> CapacityMonitoringV1FacilitiesGetLatestCircuitTransientRatingResponse200: + """ + Returns the latest circuit transient rating for a given facility: the line transient + rating capped, per duration, by the most-limiting facility component. + + The response holds one timestamp and one value per calculated duration, each with the + limiting facility component id (``None`` when the line transient rating is the binding + constraint). `since` bounds how old the returned value may be. + """ + from heimdall_api_client.capacity_monitoring import get_latest_circuit_transient_rating + + return self._execute_with_retry( + lambda: get_latest_circuit_transient_rating( + client=self._get_authenticated_client(), + facility_id=facility_id, + x_region=self._get_region(), + quantity=quantity, + since=since, + ) + ) + def get_latest_circuit_rating_forecasts( self, facility_id: UUID ) -> CapacityMonitoringV1FacilitiesGetLatestCircuitRatingForecastsResponse200: diff --git a/python/tests/integration/test_when_fetching_latest_data.py b/python/tests/integration/test_when_fetching_latest_data.py index d9fe492..6d56196 100644 --- a/python/tests/integration/test_when_fetching_latest_data.py +++ b/python/tests/integration/test_when_fetching_latest_data.py @@ -17,6 +17,7 @@ "get_latest_sag_and_clearance", "get_latest_heimdall_dlr", "get_latest_heimdall_aar", + "get_latest_line_transient_rating", ] @@ -33,6 +34,7 @@ "get_latest_heimdall_aar", "get_latest_heimdall_dlr_forecasts", "get_latest_heimdall_aar_forecasts", + "get_latest_line_transient_rating", ], ) def test_should_return_latest_line_data(api_client, line_id, assert_endpoint_responds, method_name): @@ -43,7 +45,14 @@ def test_should_return_latest_line_data(api_client, line_id, assert_endpoint_res @pytest.mark.integration -@pytest.mark.parametrize("method_name", ["get_latest_circuit_rating", "get_latest_circuit_rating_forecasts"]) +@pytest.mark.parametrize( + "method_name", + [ + "get_latest_circuit_rating", + "get_latest_circuit_rating_forecasts", + "get_latest_circuit_transient_rating", + ], +) def test_should_return_latest_facility_data(api_client, facility_id, assert_endpoint_responds, method_name): assert_endpoint_responds( lambda: getattr(api_client, method_name)(facility_id), @@ -77,12 +86,15 @@ def test_should_accept_since_on_latest_line_endpoints(api_client, line_id, asser @pytest.mark.integration -def test_should_accept_since_on_latest_circuit_rating(api_client, facility_id, assert_endpoint_responds): +@pytest.mark.parametrize("method_name", ["get_latest_circuit_rating", "get_latest_circuit_transient_rating"]) +def test_should_accept_since_on_latest_facility_endpoints( + api_client, facility_id, assert_endpoint_responds, method_name +): since = datetime.datetime.now(datetime.UTC) - datetime.timedelta(hours=6) assert_endpoint_responds( - lambda: api_client.get_latest_circuit_rating(facility_id, since=since), - f"latest circuit rating with since={since.isoformat()}", + lambda: getattr(api_client, method_name)(facility_id, since=since), + f"{method_name} with since={since.isoformat()}", ) diff --git a/python/tests/unit/test_endpoint_wrappers_resolve.py b/python/tests/unit/test_endpoint_wrappers_resolve.py index cec1d3d..a9cf26c 100644 --- a/python/tests/unit/test_endpoint_wrappers_resolve.py +++ b/python/tests/unit/test_endpoint_wrappers_resolve.py @@ -30,6 +30,8 @@ "get_latest_heimdall_arr_forecasts", "get_latest_circuit_ratring", "get_latest_circuit_rating_forecasts", + "get_latest_line_transient_rating", + "get_latest_circuit_transient_rating", "get_heimdall_dlrs", "get_heimdall_aars", "get_circuit_ratings", @@ -47,6 +49,8 @@ "get_heimdall_dlrs", "get_heimdall_aars", "get_circuit_ratings", + "get_latest_line_transient_rating", + "get_latest_circuit_transient_rating", ] @@ -78,6 +82,8 @@ def test_client_exposes_method(name: str): "get_latest_heimdall_dlr", "get_latest_heimdall_aar", "get_latest_circuit_rating", + "get_latest_line_transient_rating", + "get_latest_circuit_transient_rating", ]