Skip to content

Commit b6d6d27

Browse files
Refactor Grid interface
Previously, the Grid interface returned `None` if the microgrid was configured as an island. This update ensures that the interface consistently returns a Grid instance. This change is necessary to treat the grid connection uniformly within the microgrid, regardless of whether the microgrid is configured as an island or not. Moreover, it guarantees that the `microgrid.grid()` function always yields a Grid instance for metric retrieval. Now the rated current of the fuse is set to zero in case of an islanded microgrid. And the fuse of the grid connection point is now set to `None` when the grid connection component metadata lacks information about the fuse. Thus, a fuse set to `None` won't prevent the initialization of the Grid instance. Signed-off-by: Daniel Zullo <[email protected]>
1 parent 594c8bf commit b6d6d27

File tree

3 files changed

+52
-23
lines changed

3 files changed

+52
-23
lines changed

src/frequenz/sdk/microgrid/_data_pipeline.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -191,9 +191,7 @@ def ev_charger_pool(
191191
)
192192
return self._ev_charger_pools[key]
193193

194-
def grid(
195-
self,
196-
) -> Grid | None:
194+
def grid(self) -> Grid:
197195
"""Return the grid instance.
198196
199197
If a Grid instance doesn't exist, a new one is created and returned.
@@ -479,7 +477,7 @@ def battery_pool(
479477
return _get().battery_pool(battery_ids, name, priority)
480478

481479

482-
def grid() -> Grid | None:
480+
def grid() -> Grid:
483481
"""Return the grid instance.
484482
485483
Returns:

src/frequenz/sdk/timeseries/grid.py

Lines changed: 26 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,6 @@ class Grid:
5353
)
5454
5555
grid = microgrid.grid()
56-
assert grid, "Grid is not initialized"
5756
5857
# Get a receiver for a builtin formula
5958
grid_power_recv = grid.power.new_receiver()
@@ -62,8 +61,14 @@ class Grid:
6261
```
6362
"""
6463

65-
fuse: Fuse
66-
"""The fuse protecting the grid connection point."""
64+
fuse: Fuse | None
65+
"""The fuse protecting the grid connection point.
66+
67+
The rated current of the fuse is set to zero in case of an islanded
68+
microgrid.
69+
And the fuse is set to `None` when the grid connection component metadata
70+
lacks information about the fuse.
71+
"""
6772

6873
_formula_pool: FormulaEnginePool
6974
"""The formula engine pool to generate grid metrics."""
@@ -134,8 +139,7 @@ def initialize(
134139
135140
Raises:
136141
RuntimeError: If there is more than 1 grid connection point in the
137-
microgrid, or if the grid connection point is not initialized,
138-
or if the grid connection point does not have a fuse.
142+
microgrid, or if the grid connection point is not initialized.
139143
"""
140144
global _GRID # pylint: disable=global-statement
141145

@@ -147,7 +151,10 @@ def initialize(
147151

148152
grid_connections_count = len(grid_connections)
149153

154+
fuse: Fuse | None = None
155+
150156
if grid_connections_count == 0:
157+
fuse = Fuse(max_current=Current.zero())
151158
_logger.info(
152159
"No grid connection found for this microgrid. This is normal for an islanded microgrid."
153160
)
@@ -159,8 +166,6 @@ def initialize(
159166
if grid_connections[0].metadata is None:
160167
raise RuntimeError("Grid metadata is None")
161168

162-
fuse: Fuse | None = None
163-
164169
# The current implementation of the Component Graph fails to
165170
# effectively convert components from a dictionary representation to
166171
# the expected Component object.
@@ -172,25 +177,28 @@ def initialize(
172177
fuse = Fuse(**fuse_dict) if fuse_dict else None
173178

174179
if fuse is None:
175-
raise RuntimeError("Grid fuse is None")
180+
_logger.warning("The grid connection point does not have a fuse")
176181

177-
namespace = f"grid-{uuid.uuid4()}"
178-
formula_pool = FormulaEnginePool(
179-
namespace,
180-
channel_registry,
181-
resampler_subscription_sender,
182-
)
182+
namespace = f"grid-{uuid.uuid4()}"
183+
formula_pool = FormulaEnginePool(
184+
namespace,
185+
channel_registry,
186+
resampler_subscription_sender,
187+
)
183188

184-
_GRID = Grid(fuse, formula_pool)
189+
_GRID = Grid(fuse, formula_pool)
185190

186191

187-
def get() -> Grid | None:
192+
def get() -> Grid:
188193
"""Get the grid connection.
189194
190-
Note that a microgrid configured as an island will not have a grid
191-
connection point. For such microgrids, this function will return `None`.
195+
Note that the rated current of the fuse is set to zero in case of an
196+
islanded microgrid.
197+
And the fuse is set to `None` when the grid connection component metadata
198+
lacks information about the fuse.
192199
193200
Returns:
194201
The grid connection.
195202
"""
203+
assert _GRID, "Grid is not initialized"
196204
return _GRID

tests/microgrid/test_grid.py

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,9 @@ async def test_grid_1(mocker: MockerFixture) -> None:
4141
await mockgrid.start(mocker)
4242
grid = microgrid.grid()
4343

44-
assert grid is None
44+
assert grid
45+
assert grid.fuse
46+
assert grid.fuse.max_current == Current.from_amperes(0.0)
4547
await mockgrid.cleanup()
4648

4749

@@ -81,6 +83,27 @@ async def test_grid_2(mocker: MockerFixture) -> None:
8183
assert grid.fuse == expected_fuse
8284

8385

86+
async def test_grid_3(mocker: MockerFixture) -> None:
87+
"""Validate that microgrids with a grid connection without a fuse are instantiated."""
88+
components = {
89+
Component(1, ComponentCategory.GRID, None, GridMetadata(None)),
90+
Component(2, ComponentCategory.METER),
91+
}
92+
connections = {
93+
Connection(1, 2),
94+
}
95+
96+
# pylint: disable=protected-access
97+
graph = gr._MicrogridComponentGraph(components=components, connections=connections)
98+
99+
mockgrid = MockMicrogrid(graph=graph)
100+
await mockgrid.start(mocker)
101+
102+
grid = microgrid.grid()
103+
assert grid is not None
104+
assert grid.fuse is None
105+
106+
84107
async def test_grid_power_1(mocker: MockerFixture) -> None:
85108
"""Test the grid power formula with a grid side meter."""
86109
mockgrid = MockMicrogrid(grid_meter=True)

0 commit comments

Comments
 (0)