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
4 changes: 4 additions & 0 deletions RELEASE_NOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@

- The `ComponentGraph.components()` parameters `component_id` and `component_category` were renamed to `component_ids` and `component_categories`, respectively.

- The `GridFrequency.component` propery was renamed to `GridFrequency.source`

- The `microgrid.frequency()` method no longer supports passing the `component` parameter. Instead the best component is automatically selected.

## New Features

<!-- Here goes the main new features and examples or instructions on how to use them -->
Expand Down
35 changes: 11 additions & 24 deletions src/frequenz/sdk/microgrid/_data_pipeline.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
from frequenz.channels import Broadcast, Sender

from ..actor._actor import Actor
from ..microgrid.component import Component
from ..timeseries._base_types import PoolType
from ..timeseries._grid_frequency import GridFrequency
from ..timeseries.grid import Grid
Expand Down Expand Up @@ -119,29 +118,21 @@ def __init__(
self._grid: Grid | None = None
self._ev_charger_pools: dict[frozenset[int], EVChargerPool] = {}
self._battery_pools: dict[frozenset[int], BatteryPoolReferenceStore] = {}
self._frequency_pool: dict[int, GridFrequency] = {}
self._frequency_instance: GridFrequency | None = None

def frequency(self, component: Component | None = None) -> GridFrequency:
def frequency(self) -> GridFrequency:
"""Fetch the grid frequency for the microgrid.
Args:
component: The component to use when fetching the grid frequency. If None,
the component will be fetched from the registry.
Returns:
A GridFrequency instance.
The GridFrequency instance.
"""
if component is None:
component = GridFrequency.find_frequency_component()
if self._frequency_instance is None:
self._frequency_instance = GridFrequency(
self._data_sourcing_request_sender(),
self._channel_registry,
)

if component.component_id in self._frequency_pool:
return self._frequency_pool[component.component_id]

grid_frequency = GridFrequency(
self._data_sourcing_request_sender(), self._channel_registry, component
)
self._frequency_pool[component.component_id] = grid_frequency
return grid_frequency
return self._frequency_instance

def logical_meter(self) -> LogicalMeter:
"""Return the logical meter instance.
Expand Down Expand Up @@ -409,17 +400,13 @@ async def initialize(resampler_config: ResamplerConfig) -> None:
_DATA_PIPELINE = _DataPipeline(resampler_config)


def frequency(component: Component | None = None) -> GridFrequency:
def frequency() -> GridFrequency:
"""Return the grid frequency.
Args:
component: Optional component to get the frequency for. If not specified,
the frequency of the grid is returned.
Returns:
The grid frequency.
"""
return _get().frequency(component)
return _get().frequency()


def logical_meter() -> LogicalMeter:
Expand Down
33 changes: 17 additions & 16 deletions src/frequenz/sdk/timeseries/_grid_frequency.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,32 +49,32 @@ def __init__(
self,
data_sourcing_request_sender: Sender[ComponentMetricRequest],
channel_registry: ChannelRegistry,
component: Component,
source: Component | None = None,
):
"""Initialize the grid frequency formula generator.
Args:
data_sourcing_request_sender: The sender to use for requests.
channel_registry: The channel registry to use for the grid frequency.
component: The component to use for the grid frequency receiver. If not
provided, the first component that is either a meter, inverter or EV
charger will be used.
source: The source component to use to receive the grid frequency.
"""
self._request_sender = data_sourcing_request_sender
self._channel_registry = channel_registry
self._component = component
self._component_metric_request = create_request(component.component_id)
self._source_component = source or GridFrequency.find_frequency_source()
self._component_metric_request = create_request(
self._source_component.component_id
)

self._task: None | asyncio.Task[None] = None

@property
def component(self) -> Component:
"""The component that is used for grid frequency.
def source(self) -> Component:
"""The component that is used to fetch the grid frequency.
Returns:
The component that is used for grid frequency.
"""
return self._component
return self._source_component

def new_receiver(self) -> Receiver[Sample[Frequency]]:
"""Create a receiver for grid frequency.
Expand All @@ -89,22 +89,23 @@ def new_receiver(self) -> Receiver[Sample[Frequency]]:
if not self._task:
self._task = asyncio.create_task(self._send_request())
else:
_logger.info("Grid frequency request already sent: %s", self._component)
_logger.info(
"Grid frequency request already sent: %s", self._source_component
)

return receiver

async def _send_request(self) -> None:
"""Send the request for grid frequency."""
_logger.info("Sending request for grid frequency: %s", self._component)
await self._request_sender.send(self._component_metric_request)
_logger.info("Sent request for grid frequency: %s", self._component)
_logger.debug("Sent request for grid frequency: %s", self._source_component)

@staticmethod
def find_frequency_component() -> Component:
"""Find the component that will be used for grid frequency.
def find_frequency_source() -> Component:
"""Find the source component that will be used for grid frequency.
Uses the first meter it can find to gather the frequency. If no meter is
available, it will use the first inverter, then EV charger.
Will use the first meter it can find to gather the frequency.
If no meter is available, the first inverter will be used and finally the first EV charger.
Returns:
The component that will be used for grid frequency.
Expand Down