Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions RELEASE_NOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,13 @@ This release adds support for retrieving microgrid electrical component connecti

## Upgrading

No migration required. This is a backward-compatible feature addition.
- The `get_microgrid` and `list_microgrid_electrical_components` methods now expect an argument of type `MicrogridId`, instead of an `int`.
- The `PvInverter` type has been renamed to `SolarInverter`, to be compatible with the microgrid api client.

## New Features

- This exposes the abstract `Battery`, `EvCharger` and `Inverter` types.

### Component Connections API

* **New `ComponentConnection` class**: Introduced to represent connections between electrical components in a microgrid
Expand All @@ -18,4 +21,4 @@ No migration required. This is a backward-compatible feature addition.

## Bug Fixes

<!-- No bug fixes in this release -->
<!-- No bug fixes in this release -->
22 changes: 12 additions & 10 deletions src/frequenz/client/assets/_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
from frequenz.api.assets.v1 import assets_pb2, assets_pb2_grpc
from frequenz.client.base import channel
from frequenz.client.base.client import BaseApiClient, call_stub_method
from frequenz.client.common.microgrid import MicrogridId
from frequenz.client.common.microgrid.electrical_components import ElectricalComponentId

from ._microgrid import Microgrid
from ._microgrid_proto import microgrid_from_proto
Expand Down Expand Up @@ -87,7 +89,7 @@ def stub(self) -> assets_pb2_grpc.PlatformAssetsAsyncStub:
return self._stub # type: ignore

async def get_microgrid( # noqa: DOC502 (raises ApiClientError indirectly)
self, microgrid_id: int
self, microgrid_id: MicrogridId
) -> Microgrid:
"""
Get the details of a microgrid.
Expand All @@ -105,7 +107,7 @@ async def get_microgrid( # noqa: DOC502 (raises ApiClientError indirectly)
response = await call_stub_method(
self,
lambda: self.stub.GetMicrogrid(
assets_pb2.GetMicrogridRequest(microgrid_id=microgrid_id),
assets_pb2.GetMicrogridRequest(microgrid_id=int(microgrid_id)),
timeout=DEFAULT_GRPC_CALL_TIMEOUT,
),
method_name="GetMicrogrid",
Expand All @@ -114,7 +116,7 @@ async def get_microgrid( # noqa: DOC502 (raises ApiClientError indirectly)
return microgrid_from_proto(response.microgrid)

async def list_microgrid_electrical_components(
self, microgrid_id: int
self, microgrid_id: MicrogridId
) -> list[ElectricalComponent]:
"""
Get the electrical components of a microgrid.
Expand All @@ -129,7 +131,7 @@ async def list_microgrid_electrical_components(
self,
lambda: self.stub.ListMicrogridElectricalComponents(
assets_pb2.ListMicrogridElectricalComponentsRequest(
microgrid_id=microgrid_id,
microgrid_id=int(microgrid_id),
),
timeout=DEFAULT_GRPC_CALL_TIMEOUT,
),
Expand All @@ -142,9 +144,9 @@ async def list_microgrid_electrical_components(

async def list_microgrid_electrical_component_connections(
self,
microgrid_id: int,
source_component_ids: Iterable[int] = (),
destination_component_ids: Iterable[int] = (),
microgrid_id: MicrogridId,
source_component_ids: Iterable[ElectricalComponentId] = (),
destination_component_ids: Iterable[ElectricalComponentId] = (),
) -> list[ComponentConnection | None]:
"""
Get the electrical component connections of a microgrid.
Expand All @@ -161,9 +163,9 @@ async def list_microgrid_electrical_component_connections(
The electrical component connections of the microgrid.
"""
request = assets_pb2.ListMicrogridElectricalComponentConnectionsRequest(
microgrid_id=microgrid_id,
source_component_ids=source_component_ids,
destination_component_ids=destination_component_ids,
microgrid_id=int(microgrid_id),
source_component_ids=(int(c) for c in source_component_ids),
destination_component_ids=(int(c) for c in destination_component_ids),
)

response = await call_stub_method(
Expand Down
10 changes: 8 additions & 2 deletions src/frequenz/client/assets/electrical_component/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"""Electrical component types."""

from ._battery import (
Battery,
BatteryType,
LiIonBattery,
NaIonBattery,
Expand All @@ -22,6 +23,7 @@
from ._ev_charger import (
AcEvCharger,
DcEvCharger,
EvCharger,
EvChargerType,
HybridEvCharger,
UnrecognizedEvCharger,
Expand All @@ -32,8 +34,9 @@
from ._inverter import (
BatteryInverter,
HybridInverter,
Inverter,
InverterType,
PvInverter,
SolarInverter,
UnrecognizedInverter,
UnspecifiedInverter,
)
Expand All @@ -53,6 +56,7 @@
__all__ = [
"Chp",
"CryptoMiner",
"Battery",
"BatteryType",
"LiIonBattery",
"NaIonBattery",
Expand All @@ -66,6 +70,7 @@
"Electrolyzer",
"AcEvCharger",
"DcEvCharger",
"EvCharger",
"EvChargerType",
"HybridEvCharger",
"UnrecognizedEvCharger",
Expand All @@ -74,8 +79,9 @@
"Hvac",
"BatteryInverter",
"HybridInverter",
"Inverter",
"InverterType",
"PvInverter",
"SolarInverter",
"UnrecognizedInverter",
"UnspecifiedInverter",
"Meter",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import dataclasses
from datetime import datetime, timezone

from frequenz.client.common.microgrid.components import ComponentId
from frequenz.client.common.microgrid.electrical_components import ElectricalComponentId

from .._lifetime import Lifetime

Expand Down Expand Up @@ -38,14 +38,14 @@ class ComponentConnection:
when and how the microgrid infrastructure has been modified.
"""

source: ComponentId
source: ElectricalComponentId
"""The unique identifier of the component where the connection originates.

This is aligned with the direction of current flow away from the grid connection
point, or in case of islands, away from the islanding point.
"""

destination: ComponentId
destination: ElectricalComponentId
"""The unique ID of the component where the connection terminates.

This is the component towards which the current flows.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from frequenz.api.common.v1alpha8.microgrid.electrical_components import (
electrical_components_pb2,
)
from frequenz.client.common.microgrid.components import ComponentId
from frequenz.client.common.microgrid.electrical_components import ElectricalComponentId

from .._lifetime import Lifetime
from .._lifetime_proto import lifetime_from_proto
Expand Down Expand Up @@ -63,8 +63,10 @@ def component_connection_from_proto_with_issues(
`None` if the protobuf message is completely invalid and a
`ComponentConnection` cannot be created.
"""
source_component_id = ComponentId(message.source_electrical_component_id)
destination_component_id = ComponentId(message.destination_electrical_component_id)
source_component_id = ElectricalComponentId(message.source_electrical_component_id)
destination_component_id = ElectricalComponentId(
message.destination_electrical_component_id
)
if source_component_id == destination_component_id:
major_issues.append(
f"connection ignored: source and destination are the same ({source_component_id})",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@
BatteryInverter,
HybridInverter,
InverterType,
PvInverter,
SolarInverter,
UnrecognizedInverter,
UnspecifiedInverter,
)
Expand Down Expand Up @@ -320,12 +320,15 @@ def electrical_component_from_proto_with_issues(
inverter_enum_to_class: dict[
InverterType,
type[
UnspecifiedInverter | BatteryInverter | PvInverter | HybridInverter
UnspecifiedInverter
| BatteryInverter
| SolarInverter
| HybridInverter
],
] = {
InverterType.UNSPECIFIED: UnspecifiedInverter,
InverterType.BATTERY: BatteryInverter,
InverterType.PV: PvInverter,
InverterType.SOLAR: SolarInverter,
InverterType.HYBRID: HybridInverter,
}
inverter_type = enum_proto.enum_from_proto(
Expand All @@ -335,7 +338,7 @@ def electrical_component_from_proto_with_issues(
case (
InverterType.UNSPECIFIED
| InverterType.BATTERY
| InverterType.PV
| InverterType.SOLAR
| InverterType.HYBRID
):
if inverter_type is InverterType.UNSPECIFIED:
Expand Down
10 changes: 5 additions & 5 deletions src/frequenz/client/assets/electrical_component/_inverter.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ class InverterType(enum.Enum):
BATTERY = electrical_components_pb2.INVERTER_TYPE_BATTERY
"""The inverter is a battery inverter."""

PV = electrical_components_pb2.INVERTER_TYPE_PV
SOLAR = electrical_components_pb2.INVERTER_TYPE_PV
"""The inverter is a solar inverter."""

HYBRID = electrical_components_pb2.INVERTER_TYPE_HYBRID
Expand Down Expand Up @@ -106,10 +106,10 @@ class BatteryInverter(Inverter):


@dataclasses.dataclass(frozen=True, kw_only=True)
class PvInverter(Inverter):
"""A PV inverter."""
class SolarInverter(Inverter):
"""A Solar inverter."""

type: Literal[InverterType.PV] = InverterType.PV
type: Literal[InverterType.SOLAR] = InverterType.SOLAR
"""The type of this inverter.

Note:
Expand Down Expand Up @@ -150,7 +150,7 @@ class UnrecognizedInverter(Inverter):
InverterTypes: TypeAlias = (
UnspecifiedInverter
| BatteryInverter
| PvInverter
| SolarInverter
| HybridInverter
| UnrecognizedInverter
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
electrical_components_pb2,
)
from frequenz.client.base.conversion import to_timestamp
from frequenz.client.common.microgrid.components import ComponentId
from frequenz.client.common.microgrid.electrical_components import ElectricalComponentId

from frequenz.client.assets import Lifetime
from frequenz.client.assets.electrical_component import ComponentConnection
Expand Down Expand Up @@ -50,12 +50,12 @@ def assert_client_result(actual_result: Any) -> None:
"""Assert that the client result matches the expected connections list."""
assert list(actual_result) == [
ComponentConnection(
source=ComponentId(1),
destination=ComponentId(2),
source=ElectricalComponentId(1),
destination=ElectricalComponentId(2),
),
ComponentConnection(
source=ComponentId(2),
destination=ComponentId(3),
source=ElectricalComponentId(2),
destination=ElectricalComponentId(3),
operational_lifetime=Lifetime(start=lifetime_start),
),
]