Skip to content

Commit 5e3d475

Browse files
committed
Fix consumer_power() not working certain configurations.
In microgrids without consumers and no main meter, the formula would never return any values. Signed-off-by: Mathias L. Baumann <[email protected]>
1 parent bbc2bcd commit 5e3d475

File tree

3 files changed

+39
-1
lines changed

3 files changed

+39
-1
lines changed

RELEASE_NOTES.md

+3
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,6 @@
1919
component.
2020
So far we only had configurations like this: Meter -> Inverter -> PV. However
2121
the scenario with Inverter -> PV is also possible and now handled correctly.
22+
- Fix `consumer_power()` not working certain configurations.
23+
In microgrids without consumers and no main meter, the formula
24+
would never return any values.

src/frequenz/sdk/timeseries/_formula_engine/_formula_generators/_consumer_power_formula.py

+21-1
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,21 @@
55

66
from __future__ import annotations
77

8+
import logging
89
from collections import abc
910

1011
from ....microgrid import connection_manager
1112
from ....microgrid.component import Component, ComponentCategory, ComponentMetricId
1213
from ..._quantities import Power
1314
from .._formula_engine import FormulaEngine
1415
from .._resampled_formula_builder import ResampledFormulaBuilder
15-
from ._formula_generator import ComponentNotFound, FormulaGenerator
16+
from ._formula_generator import (
17+
NON_EXISTING_COMPONENT_ID,
18+
ComponentNotFound,
19+
FormulaGenerator,
20+
)
21+
22+
_logger = logging.getLogger(__name__)
1623

1724

1825
class ConsumerPowerFormula(FormulaGenerator[Power]):
@@ -121,4 +128,17 @@ def _gen_without_grid_meter(
121128
is_first = False
122129
builder.push_component_metric(successor.component_id, nones_are_zeros=False)
123130

131+
if len(builder.finalize()[0]) == 0:
132+
# If there are no consumer components, we have to send 0 values at the same
133+
# frequency as the other streams. So we subscribe with a non-existing
134+
# component id, just to get a `None` message at the resampling interval.
135+
builder.push_component_metric(
136+
NON_EXISTING_COMPONENT_ID, nones_are_zeros=True
137+
)
138+
_logger.warning(
139+
"Unable to find any consumers in the component graph. "
140+
"Subscribing to the resampling actor with a non-existing "
141+
"component id, so that `0` values are sent from the formula."
142+
)
143+
124144
return builder.build()

tests/timeseries/test_logical_meter.py

+15
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,21 @@ async def test_consumer_power_no_grid_meter(self, mocker: MockerFixture) -> None
266266
await mockgrid.mock_resampler.send_meter_power([20.0, 2.0, 3.0, 4.0, 5.0])
267267
assert (await consumer_power_receiver.receive()).value == Power.from_watts(20.0)
268268

269+
async def test_consumer_power_no_grid_meter_no_consumer_meter(
270+
self, mocker: MockerFixture
271+
) -> None:
272+
"""Test the consumer power formula without a grid meter."""
273+
mockgrid = MockMicrogrid(grid_meter=False)
274+
mockgrid.add_batteries(2)
275+
mockgrid.add_solar_inverters(2)
276+
await mockgrid.start(mocker)
277+
278+
logical_meter = microgrid.logical_meter()
279+
consumer_power_receiver = logical_meter.consumer_power.new_receiver()
280+
281+
await mockgrid.mock_resampler.send_non_existing_component_value()
282+
assert (await consumer_power_receiver.receive()).value == Power.from_watts(0.0)
283+
269284
async def test_producer_power(self, mocker: MockerFixture) -> None:
270285
"""Test the producer power formula."""
271286
mockgrid = MockMicrogrid(grid_meter=False)

0 commit comments

Comments
 (0)