Skip to content

Commit a3a46ac

Browse files
Use fuse in GridMetadata
This commit uses a Fuse object to represent the max current limit in component metadata in the internal layer that parses components objects obtained directly from the Microgrid API. This makes the abstraction of fuses one level deeper, increasing the chances of the `grid_connection.py` file being more stable in the future if/when further changes are introduced in the Microgrid API. Signed-off-by: Tiyash Basu <[email protected]>
1 parent 7feb797 commit a3a46ac

File tree

5 files changed

+59
-21
lines changed

5 files changed

+59
-21
lines changed

src/frequenz/sdk/microgrid/component/_component.py

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
from __future__ import annotations
77

88
import typing
9+
from abc import ABC, abstractmethod
910
from dataclasses import dataclass
1011
from enum import Enum
1112
from typing import Optional
@@ -14,6 +15,9 @@
1415
import frequenz.api.microgrid.grid_pb2 as grid_pb
1516
import frequenz.api.microgrid.inverter_pb2 as inverter_pb
1617

18+
from ...timeseries import Current
19+
from ..fuse import Fuse
20+
1721

1822
class ComponentType(Enum):
1923
"""A base class from which individual component types are derived."""
@@ -108,29 +112,41 @@ def _component_category_from_protobuf(
108112
return ComponentCategory(component_category)
109113

110114

111-
class ComponentMetadata:
115+
class ComponentMetadata(ABC):
112116
"""Base class for component metadata classes."""
113117

118+
@property
119+
@abstractmethod
120+
def fuse(self) -> Optional[Fuse]:
121+
"""Get the fuse associated with this component.
122+
123+
Returns:
124+
The fuse associated with this component.
125+
"""
126+
114127

115128
class GridMetadata(ComponentMetadata):
116129
"""Metadata for a grid connection point."""
117130

118-
def __init__(self, max_current: float) -> None:
131+
def __init__(self, fuse: Fuse) -> None:
119132
"""Create a new instance.
120133
121134
Args:
122-
max_current: maximum current rating of the grid connection point in amps.
135+
fuse: The fuse at the grid connection point.
123136
"""
124-
self._max_current = max_current
137+
self._fuse = fuse
125138

126139
@property
127-
def max_current(self) -> float:
128-
"""Get the maximum current rating of the grid connection point.
140+
def fuse(self) -> Optional[Fuse]:
141+
"""Get the fuse at the grid connection point.
129142
130143
Returns:
131-
Maximum current rating in amps.
144+
The fuse at the grid connection point.
132145
"""
133-
return self._max_current
146+
if not isinstance(self, GridMetadata):
147+
return None
148+
149+
return self._fuse
134150

135151
def __eq__(self, other: typing.Any) -> bool:
136152
"""Check if this instance is equal to another.
@@ -139,21 +155,23 @@ def __eq__(self, other: typing.Any) -> bool:
139155
other: object to compare to.
140156
141157
Returns:
142-
`True` if `other` is a `GridMetadata` instance and `max_current` is equal,
158+
`True` if `other` is a `GridMetadata` instance and `fuse` is equal,
143159
`False` otherwise.
144160
"""
145161
if not isinstance(other, GridMetadata):
146162
return False
147163

148-
return self.max_current == other.max_current
164+
return self.fuse == other.fuse
149165

150166

151167
def _component_metadata_from_protobuf(
152168
component_category: components_pb.ComponentCategory.ValueType,
153169
component_metadata: grid_pb.Metadata,
154170
) -> Optional[GridMetadata]:
155171
if component_category == components_pb.ComponentCategory.COMPONENT_CATEGORY_GRID:
156-
return GridMetadata(float(component_metadata.rated_fuse_current))
172+
max_current = Current.from_amperes(component_metadata.rated_fuse_current)
173+
fuse = Fuse(max_current)
174+
return GridMetadata(fuse)
157175

158176
return None
159177

src/frequenz/sdk/microgrid/grid.py

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
from dataclasses import dataclass
1212
from typing import Iterable, Optional
1313

14-
from ..timeseries import Current
1514
from .component import Component
1615
from .component._component import ComponentCategory
1716
from .fuse import Fuse
@@ -36,7 +35,8 @@ def initialize(components: Iterable[Component]) -> None:
3635
3736
Raises:
3837
RuntimeError: If there is more than 1 grid connection point in the
39-
microgrid.
38+
microgrid, or if the grid connection point is not initialized,
39+
or if the grid connection point does not have a fuse.
4040
"""
4141
global _GRID # pylint: disable=global-statement
4242

@@ -57,8 +57,14 @@ def initialize(components: Iterable[Component]) -> None:
5757
f"Expected at most one grid connection, got {grid_connections_count}"
5858
)
5959
else:
60-
max_current = grid_connections[0].metadata.max_current # type: ignore
61-
fuse = Fuse(Current.from_amperes(max_current))
60+
if grid_connections[0].metadata is None:
61+
raise RuntimeError("Grid metadata is None")
62+
63+
fuse = grid_connections[0].metadata.fuse
64+
65+
if fuse is None:
66+
raise RuntimeError("Grid fuse is None")
67+
6268
_GRID = Grid(fuse)
6369

6470

tests/microgrid/test_client.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@
2626
InverterType,
2727
MeterData,
2828
)
29+
from frequenz.sdk.microgrid.fuse import Fuse
30+
from frequenz.sdk.timeseries import Current
2931

3032
from . import mock_api
3133

@@ -122,10 +124,13 @@ async def test_components(self) -> None:
122124
101, components_pb.ComponentCategory.COMPONENT_CATEGORY_GRID, 123
123125
)
124126

127+
grid_max_current = Current.from_amperes(123.0)
128+
grid_fuse = Fuse(grid_max_current)
129+
125130
assert set(await microgrid.components()) == {
126131
Component(100, ComponentCategory.NONE),
127132
Component(
128-
101, ComponentCategory.GRID, None, GridMetadata(max_current=123.0)
133+
101, ComponentCategory.GRID, None, GridMetadata(fuse=grid_fuse)
129134
),
130135
Component(104, ComponentCategory.METER),
131136
Component(105, ComponentCategory.INVERTER, InverterType.NONE),

tests/microgrid/test_graph.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
GridMetadata,
2525
InverterType,
2626
)
27+
from frequenz.sdk.microgrid.fuse import Fuse
28+
from frequenz.sdk.timeseries import Current
2729

2830
from .mock_api import MockGrpcServer, MockMicrogridServicer
2931

@@ -821,8 +823,11 @@ async def test_refresh_from_api(self) -> None:
821823
servicer.set_connections([(101, 111), (111, 131)])
822824
await graph.refresh_from_api(client)
823825

826+
grid_max_current = Current.from_amperes(0.0)
827+
grid_fuse = Fuse(grid_max_current)
828+
824829
expected = {
825-
Component(101, ComponentCategory.GRID, None, GridMetadata(max_current=0.0)),
830+
Component(101, ComponentCategory.GRID, None, GridMetadata(fuse=grid_fuse)),
826831
Component(111, ComponentCategory.METER),
827832
Component(131, ComponentCategory.EV_CHARGER),
828833
}
@@ -847,8 +852,9 @@ async def test_refresh_from_api(self) -> None:
847852
)
848853
servicer.set_connections([(707, 717), (717, 727), (727, 737), (717, 747)])
849854
await graph.refresh_from_api(client)
855+
850856
expected = {
851-
Component(707, ComponentCategory.GRID, None, GridMetadata(max_current=0.0)),
857+
Component(707, ComponentCategory.GRID, None, GridMetadata(fuse=grid_fuse)),
852858
Component(717, ComponentCategory.METER),
853859
Component(727, ComponentCategory.INVERTER, InverterType.NONE),
854860
Component(737, ComponentCategory.BATTERY),

tests/microgrid/test_grid.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,12 @@ async def test_grid() -> None:
3131

3232
# validate that the microgrid initialization fails when there are multiple
3333
# grid connection points.
34+
fuse_current = Current.from_amperes(123.0)
35+
fuse = Fuse(fuse_current)
36+
3437
components = [
35-
Component(1, ComponentCategory.GRID, None, GridMetadata(123.0)),
36-
Component(2, ComponentCategory.GRID, None, GridMetadata(345.0)),
38+
Component(1, ComponentCategory.GRID, None, GridMetadata(fuse)),
39+
Component(2, ComponentCategory.GRID, None, GridMetadata(fuse)),
3740
Component(3, ComponentCategory.METER),
3841
]
3942

@@ -48,7 +51,7 @@ async def test_grid() -> None:
4851

4952
# validate that microgrids with one grid connection are accepted.
5053
components = [
51-
Component(1, ComponentCategory.GRID, None, GridMetadata(123.0)),
54+
Component(1, ComponentCategory.GRID, None, GridMetadata(fuse)),
5255
Component(2, ComponentCategory.METER),
5356
]
5457

0 commit comments

Comments
 (0)