Skip to content

Commit 8e39de5

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 component 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 7b4246e commit 8e39de5

File tree

5 files changed

+58
-21
lines changed

5 files changed

+58
-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,13 +6,17 @@
66
from __future__ import annotations
77

88
import typing
9+
from abc import ABC
910
from dataclasses import dataclass
1011
from enum import Enum
1112

1213
import frequenz.api.common.components_pb2 as components_pb
1314
import frequenz.api.microgrid.grid_pb2 as grid_pb
1415
import frequenz.api.microgrid.inverter_pb2 as inverter_pb
1516

17+
from ...timeseries import Current
18+
from ..fuse import Fuse
19+
1620

1721
class ComponentType(Enum):
1822
"""A base class from which individual component types are derived."""
@@ -107,29 +111,41 @@ def _component_category_from_protobuf(
107111
return ComponentCategory(component_category)
108112

109113

110-
class ComponentMetadata:
114+
class ComponentMetadata(ABC):
111115
"""Base class for component metadata classes."""
112116

117+
@property
118+
def fuse(self) -> Fuse | None:
119+
"""Get the fuse associated with this component.
120+
121+
Returns:
122+
The fuse associated with this component.
123+
"""
124+
return None
125+
113126

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

117-
def __init__(self, max_current: float) -> None:
130+
def __init__(self, fuse: Fuse) -> None:
118131
"""Create a new instance.
119132
120133
Args:
121-
max_current: maximum current rating of the grid connection point in amps.
134+
fuse: The fuse at the grid connection point.
122135
"""
123-
self._max_current = max_current
136+
self._fuse = fuse
124137

125138
@property
126-
def max_current(self) -> float:
127-
"""Get the maximum current rating of the grid connection point.
139+
def fuse(self) -> Fuse | None:
140+
"""Get the fuse at the grid connection point.
128141
129142
Returns:
130-
Maximum current rating in amps.
143+
None, by default.
131144
"""
132-
return self._max_current
145+
if not isinstance(self, GridMetadata):
146+
return None
147+
148+
return self._fuse
133149

134150
def __eq__(self, other: typing.Any) -> bool:
135151
"""Check if this instance is equal to another.
@@ -138,21 +154,23 @@ def __eq__(self, other: typing.Any) -> bool:
138154
other: object to compare to.
139155
140156
Returns:
141-
`True` if `other` is a `GridMetadata` instance and `max_current` is equal,
157+
`True` if `other` is a `GridMetadata` instance and `fuse` is equal,
142158
`False` otherwise.
143159
"""
144160
if not isinstance(other, GridMetadata):
145161
return False
146162

147-
return self.max_current == other.max_current
163+
return self.fuse == other.fuse
148164

149165

150166
def _component_metadata_from_protobuf(
151167
component_category: components_pb.ComponentCategory.ValueType,
152168
component_metadata: grid_pb.Metadata,
153169
) -> GridMetadata | None:
154170
if component_category == components_pb.ComponentCategory.COMPONENT_CATEGORY_GRID:
155-
return GridMetadata(float(component_metadata.rated_fuse_current))
171+
max_current = Current.from_amperes(component_metadata.rated_fuse_current)
172+
fuse = Fuse(max_current)
173+
return GridMetadata(fuse)
156174

157175
return None
158176

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: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
InverterType,
2727
MeterData,
2828
)
29+
from frequenz.sdk.microgrid.fuse import Fuse
2930
from frequenz.sdk.timeseries import Current
3031

3132
from . import mock_api
@@ -125,10 +126,13 @@ async def test_components(self) -> None:
125126
Current.from_amperes(123.0),
126127
)
127128

129+
grid_max_current = Current.from_amperes(123.0)
130+
grid_fuse = Fuse(grid_max_current)
131+
128132
assert set(await microgrid.components()) == {
129133
Component(100, ComponentCategory.NONE),
130134
Component(
131-
101, ComponentCategory.GRID, None, GridMetadata(max_current=123.0)
135+
101, ComponentCategory.GRID, None, GridMetadata(fuse=grid_fuse)
132136
),
133137
Component(104, ComponentCategory.METER),
134138
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.zero()
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)