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
2 changes: 1 addition & 1 deletion RELEASE_NOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

## New Features

<!-- Here goes the main new features and examples or instructions on how to use them -->
- The power manager algorithm for batteries can now be changed from the default ShiftingMatryoshka, by passing it as an argument to `microgrid.initialize()`

## Bug Fixes

Expand Down
7 changes: 7 additions & 0 deletions src/frequenz/sdk/microgrid/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -383,13 +383,16 @@
producer,
voltage_per_phase,
)
from ._power_managing import PowerManagerAlgorithm


async def initialize(
server_url: str,
resampler_config: ResamplerConfig,
*,
api_power_request_timeout: timedelta = timedelta(seconds=5.0),
# pylint: disable-next: line-too-long
battery_power_manager_algorithm: PowerManagerAlgorithm = PowerManagerAlgorithm.SHIFTING_MATRYOSHKA, # noqa: E501
Copy link
Contributor

Choose a reason for hiding this comment

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

I guess this is needed somehow soon, but in the future I think it might make more sense to have copy what we have with the resampler_config and add a power_manager_config: PowerManagerConfig, and in there it can have something like power_manager_config.battery.algorithm` for example.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

) -> None:
"""Initialize the microgrid connection manager and the data pipeline.

Expand All @@ -404,15 +407,19 @@ async def initialize(
the microgrid API. When requests to components timeout, they will
be marked as blocked for a short duration, during which time they
will be unavailable from the corresponding component pools.
battery_power_manager_algorithm: The power manager algorithm to use for
batteries.
"""
await connection_manager.initialize(server_url)
await _data_pipeline.initialize(
resampler_config,
api_power_request_timeout=api_power_request_timeout,
battery_power_manager_algorithm=battery_power_manager_algorithm,
)


__all__ = [
"PowerManagerAlgorithm",
"initialize",
"consumer",
"grid",
Expand Down
19 changes: 13 additions & 6 deletions src/frequenz/sdk/microgrid/_data_pipeline.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,12 @@
from frequenz.client.common.microgrid.components import ComponentId
from frequenz.client.microgrid.component import Battery, EvCharger, SolarInverter

from frequenz.sdk.microgrid._power_managing._base_classes import Algorithm, DefaultPower

from .._internal._channels import ChannelRegistry
from ..actor._actor import Actor
from ..timeseries import ResamplerConfig
from ..timeseries._voltage_streamer import VoltageStreamer
from ._data_sourcing import ComponentMetricRequest, DataSourcingActor
from ._power_managing._base_classes import DefaultPower, PowerManagerAlgorithm
from ._power_wrapper import PowerWrapper

# A number of imports had to be done inside functions where they are used, to break
Expand Down Expand Up @@ -84,13 +83,16 @@ def __init__(
self,
resampler_config: ResamplerConfig,
api_power_request_timeout: timedelta = timedelta(seconds=5.0),
battery_power_manager_algorithm: PowerManagerAlgorithm = PowerManagerAlgorithm.SHIFTING_MATRYOSHKA, # noqa: E501
) -> None:
"""Create a `DataPipeline` instance.

Args:
resampler_config: Config to pass on to the resampler.
api_power_request_timeout: Timeout to use when making power requests to
the microgrid API.
battery_power_manager_algorithm: The power manager algorithm to use for
batteries.
"""
self._resampler_config: ResamplerConfig = resampler_config

Expand All @@ -104,21 +106,21 @@ def __init__(
self._battery_power_wrapper = PowerWrapper(
self._channel_registry,
api_power_request_timeout=api_power_request_timeout,
power_manager_algorithm=Algorithm.SHIFTING_MATRYOSHKA,
power_manager_algorithm=battery_power_manager_algorithm,
default_power=DefaultPower.ZERO,
component_class=Battery,
)
self._ev_power_wrapper = PowerWrapper(
self._channel_registry,
api_power_request_timeout=api_power_request_timeout,
power_manager_algorithm=Algorithm.MATRYOSHKA,
power_manager_algorithm=PowerManagerAlgorithm.MATRYOSHKA,
default_power=DefaultPower.MAX,
component_class=EvCharger,
)
self._pv_power_wrapper = PowerWrapper(
self._channel_registry,
api_power_request_timeout=api_power_request_timeout,
power_manager_algorithm=Algorithm.MATRYOSHKA,
power_manager_algorithm=PowerManagerAlgorithm.MATRYOSHKA,
default_power=DefaultPower.MIN,
# Using SolarInverter might be too specific, maybe we need to also pass
# HybridInverter, see
Expand Down Expand Up @@ -515,6 +517,7 @@ async def _stop(self) -> None:
async def initialize(
resampler_config: ResamplerConfig,
api_power_request_timeout: timedelta = timedelta(seconds=5.0),
battery_power_manager_algorithm: PowerManagerAlgorithm = PowerManagerAlgorithm.SHIFTING_MATRYOSHKA, # noqa: E501
) -> None:
"""Initialize a `DataPipeline` instance.

Expand All @@ -524,6 +527,8 @@ async def initialize(
the microgrid API. When requests to components timeout, they will
be marked as blocked for a short duration, during which time they
will be unavailable from the corresponding component pools.
battery_power_manager_algorithm: The power manager algorithm to use for
batteries.

Raises:
RuntimeError: if the DataPipeline is already initialized.
Expand All @@ -532,7 +537,9 @@ async def initialize(

if _DATA_PIPELINE is not None:
raise RuntimeError("DataPipeline is already initialized.")
_DATA_PIPELINE = _DataPipeline(resampler_config, api_power_request_timeout)
_DATA_PIPELINE = _DataPipeline(
resampler_config, api_power_request_timeout, battery_power_manager_algorithm
)


def frequency() -> GridFrequency:
Expand Down
4 changes: 2 additions & 2 deletions src/frequenz/sdk/microgrid/_power_managing/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@

"""A power manager implementation."""

from ._base_classes import Algorithm, Proposal, ReportRequest, _Report
from ._base_classes import PowerManagerAlgorithm, Proposal, ReportRequest, _Report
from ._power_managing_actor import PowerManagingActor

__all__ = [
"Algorithm",
"PowerManagerAlgorithm",
"PowerManagingActor",
"Proposal",
"_Report",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ class DefaultPower(enum.Enum):
"""The default power is the maximum power of the component."""


class Algorithm(enum.Enum):
class PowerManagerAlgorithm(enum.Enum):
"""The available algorithms for the power manager."""

MATRYOSHKA = "matryoshka"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@
from ...timeseries._base_types import SystemBounds
from .. import _data_pipeline, _power_distributing
from ._base_classes import (
Algorithm,
BaseAlgorithm,
DefaultPower,
PowerManagerAlgorithm,
Proposal,
ReportRequest,
_Report,
Expand All @@ -47,7 +47,7 @@ def __init__( # pylint: disable=too-many-arguments
power_distributing_requests_sender: Sender[_power_distributing.Request],
power_distributing_results_receiver: Receiver[_power_distributing.Result],
channel_registry: ChannelRegistry,
algorithm: Algorithm,
algorithm: PowerManagerAlgorithm,
default_power: DefaultPower,
component_class: type[Battery | EvCharger | SolarInverter],
):
Expand Down Expand Up @@ -80,12 +80,12 @@ def __init__( # pylint: disable=too-many-arguments
] = {}

match algorithm:
case Algorithm.MATRYOSHKA:
case PowerManagerAlgorithm.MATRYOSHKA:
self._algorithm: BaseAlgorithm = Matryoshka(
max_proposal_age=timedelta(seconds=60.0),
default_power=default_power,
)
case Algorithm.SHIFTING_MATRYOSHKA:
case PowerManagerAlgorithm.SHIFTING_MATRYOSHKA:
self._algorithm = ShiftingMatryoshka(
max_proposal_age=timedelta(seconds=60.0),
default_power=default_power,
Expand Down
4 changes: 2 additions & 2 deletions src/frequenz/sdk/microgrid/_power_wrapper.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
Request,
Result,
)
from ._power_managing._base_classes import Algorithm, DefaultPower
from ._power_managing._base_classes import DefaultPower, PowerManagerAlgorithm

_logger = logging.getLogger(__name__)

Expand All @@ -38,7 +38,7 @@ def __init__( # pylint: disable=too-many-arguments
channel_registry: ChannelRegistry,
*,
api_power_request_timeout: timedelta,
power_manager_algorithm: Algorithm,
power_manager_algorithm: PowerManagerAlgorithm,
default_power: DefaultPower,
component_class: type[Battery | EvCharger | SolarInverter],
):
Expand Down