Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Redesign access to migrogrid.grid() #707

Merged
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
4 changes: 4 additions & 0 deletions RELEASE_NOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ This version ships an experimental version of the **Power Manager**, adds prelim

- `microgrid.battery_pool()` method now accepts a priority value.

- `microgrid.grid()`

* Similar to `microgrid.battery_pool()`, the Grid is now similarily accessed.

- `BatteryPool`'s control methods

* Original methods `{set_power/charge/discharge}` are now replaced by `propose_{power/charge/discharge}`
Expand Down
13 changes: 10 additions & 3 deletions src/frequenz/sdk/microgrid/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,8 +123,15 @@
""" # noqa: D205, D400

from ..actor import ResamplerConfig
from . import _data_pipeline, client, component, connection_manager, fuse, grid
from ._data_pipeline import battery_pool, ev_charger_pool, frequency, logical_meter
from . import _data_pipeline, client, component, connection_manager, fuse
from ._data_pipeline import (
battery_pool,
ev_charger_pool,
frequency,
grid,
logical_meter,
)
from ._grid import initialize as initialize_grid


async def initialize(host: str, port: int, resampler_config: ResamplerConfig) -> None:
Expand All @@ -139,7 +146,7 @@ async def initialize(host: str, port: int, resampler_config: ResamplerConfig) ->

api_client = connection_manager.get().api_client
components = await api_client.components()
grid.initialize(components)
initialize_grid(components)

await _data_pipeline.initialize(resampler_config)

Expand Down
23 changes: 23 additions & 0 deletions src/frequenz/sdk/microgrid/_data_pipeline.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
from ..microgrid.component import Component
from ..timeseries._grid_frequency import GridFrequency
from . import connection_manager
from ._grid import Grid
from ._grid import get as get_grid
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just in case, FYI, you can still do:

from ._grid import Grid
from . import _grid

And use _grid.get() for example for the internal stuff, and use Grid for the public stuff.

from .component import ComponentCategory

_logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -186,6 +188,18 @@ def ev_charger_pool(
)
return self._ev_charger_pools[key]

def grid(
self,
) -> Grid | None:
"""Return the grid instance.

If a Grid instance doesn't exist, a new one is created and returned.

Returns:
A Grid instance.
"""
return get_grid()

def battery_pool(
self,
battery_ids: abc.Set[int] | None = None,
Expand Down Expand Up @@ -454,6 +468,15 @@ def battery_pool(
return _get().battery_pool(battery_ids, name, priority)


def grid() -> Grid | None:
"""Return the grid instance.

Returns:
The Grid instance.
"""
return _get().grid()


def _get() -> _DataPipeline:
if _DATA_PIPELINE is None:
raise RuntimeError(
Expand Down
47 changes: 29 additions & 18 deletions tests/microgrid/test_grid.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,13 @@

"""Tests for the `Grid` module."""

from frequenz.sdk import microgrid
from frequenz.sdk.microgrid import _grid
from frequenz.sdk.microgrid.component import Component, ComponentCategory, GridMetadata
from frequenz.sdk.microgrid.fuse import Fuse
from frequenz.sdk.microgrid.grid import Grid
from frequenz.sdk.timeseries import Current


async def test_grid() -> None:
async def test_grid_1() -> None:
"""Test the grid connection module."""
# The tests here need to be in this exact sequence, because the grid connection
# is a singleton. Once it gets created, it stays in memory for the duration of
Expand All @@ -21,15 +20,29 @@ async def test_grid() -> None:
Component(2, ComponentCategory.METER),
]

microgrid.grid.initialize(components)

grid = microgrid.grid.get()
_grid.initialize(components)
grid = _grid.get()
assert grid is None

# validate that the microgrid initialization fails when there are multiple
# grid connection points.

def _create_fuse() -> Fuse:
"""Create a fuse with a fixed current.

Returns:
Fuse: The fuse.
"""
fuse_current = Current.from_amperes(123.0)
fuse = Fuse(fuse_current)
return fuse


async def test_grid_2() -> None:
"""Test the grid connection module, slightly more complex.

Validate that the microgrid initialization fails
when there are multiple grid connection points.
"""
fuse = _create_fuse()

components = [
Component(1, ComponentCategory.GRID, None, GridMetadata(fuse)),
Expand All @@ -38,29 +51,27 @@ async def test_grid() -> None:
]

try:
microgrid.grid.initialize(components)
assert False, "Expected microgrid.grid.initialize to raise a RuntimeError."
_grid.initialize(components)
assert False, "Expected microgrid.grid() to raise a RuntimeError."
except RuntimeError:
pass

grid = microgrid.grid.get()
assert grid is None

# validate that microgrids with one grid connection are accepted.
async def test_grid_3() -> None:
"""Validate that microgrids with one grid connection are accepted."""
components = [
Component(1, ComponentCategory.GRID, None, GridMetadata(fuse)),
Component(1, ComponentCategory.GRID, None, GridMetadata(_create_fuse())),
Component(2, ComponentCategory.METER),
]

microgrid.grid.initialize(components)

grid = microgrid.grid.get()
_grid.initialize(components)
grid = _grid.get()
assert grid is not None

expected_fuse_current = Current.from_amperes(123.0)
expected_fuse = Fuse(expected_fuse_current)

assert grid == Grid(fuse=expected_fuse)
assert grid == _grid.Grid(fuse=expected_fuse)

fuse_current = grid.fuse.max_current
assert fuse_current == expected_fuse_current