Skip to content

Commit c892823

Browse files
committed
Use Sample[Quantity] to stream BatteryPool.soc values
A custom type is no longer necessary because there are no additional fields like bounds that need to be streamed with SoC values. Signed-off-by: Sahas Subramanian <[email protected]>
1 parent 163d993 commit c892823

File tree

3 files changed

+27
-25
lines changed

3 files changed

+27
-25
lines changed

src/frequenz/sdk/timeseries/battery_pool/_metric_calculator.py

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,9 @@
1212

1313
from ...microgrid import connection_manager
1414
from ...microgrid.component import ComponentCategory, ComponentMetricId, InverterType
15+
from ...timeseries import Quantity, Sample
1516
from ._component_metrics import ComponentMetricsData
16-
from ._result_types import Bound, CapacityMetrics, PowerMetrics, SoCMetrics
17+
from ._result_types import Bound, CapacityMetrics, PowerMetrics
1718

1819
_logger = logging.getLogger(__name__)
1920
_MIN_TIMESTAMP = datetime.min.replace(tzinfo=timezone.utc)
@@ -58,7 +59,7 @@ def battery_inverter_mapping(batteries: Iterable[int]) -> dict[int, int]:
5859

5960
# Formula output types class have no common interface
6061
# Print all possible types here.
61-
T = TypeVar("T", SoCMetrics, CapacityMetrics, PowerMetrics)
62+
T = TypeVar("T", Sample[Quantity], CapacityMetrics, PowerMetrics)
6263

6364

6465
class MetricCalculator(ABC, Generic[T]):
@@ -228,7 +229,7 @@ def calculate(
228229
return None if result.timestamp == _MIN_TIMESTAMP else result
229230

230231

231-
class SoCCalculator(MetricCalculator[SoCMetrics]):
232+
class SoCCalculator(MetricCalculator[Sample[Quantity]]):
232233
"""Define how to calculate SoC metrics."""
233234

234235
def __init__(self, batteries: Set[int]) -> None:
@@ -277,7 +278,7 @@ def calculate(
277278
self,
278279
metrics_data: dict[int, ComponentMetricsData],
279280
working_batteries: set[int],
280-
) -> SoCMetrics | None:
281+
) -> Sample[Quantity] | None:
281282
"""Aggregate the metrics_data and calculate high level metric.
282283
283284
Missing components will be ignored. Formula will be calculated for all
@@ -341,13 +342,13 @@ def calculate(
341342

342343
# To avoid zero division error
343344
if total_capacity_x100 == 0:
344-
return SoCMetrics(
345+
return Sample(
345346
timestamp=timestamp,
346-
average_soc=0,
347+
value=Quantity(0.0),
347348
)
348-
return SoCMetrics(
349+
return Sample(
349350
timestamp=timestamp,
350-
average_soc=used_capacity_x100 / total_capacity_x100,
351+
value=Quantity(used_capacity_x100 / total_capacity_x100),
351352
)
352353

353354

src/frequenz/sdk/timeseries/battery_pool/battery_pool.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
from ...actor.power_distributing.result import Result
2121
from ...microgrid import connection_manager
2222
from ...microgrid.component import ComponentCategory
23+
from ...timeseries import Quantity, Sample
2324
from .._formula_engine import FormulaEngine, FormulaEnginePool
2425
from .._formula_engine._formula_generators import (
2526
BatteryPowerFormula,
@@ -29,7 +30,7 @@
2930
from .._quantities import Power
3031
from ._methods import MetricAggregator, SendOnUpdate
3132
from ._metric_calculator import CapacityCalculator, PowerBoundsCalculator, SoCCalculator
32-
from ._result_types import CapacityMetrics, PowerMetrics, SoCMetrics
33+
from ._result_types import CapacityMetrics, PowerMetrics
3334

3435

3536
class BatteryPool:
@@ -329,7 +330,7 @@ def consumption_power(self) -> FormulaEngine[Power]:
329330
return engine
330331

331332
@property
332-
def soc(self) -> MetricAggregator[SoCMetrics]:
333+
def soc(self) -> MetricAggregator[Sample[Quantity]]:
333334
"""Fetch the normalized average weighted-by-capacity SoC values for the pool.
334335
335336
The formulas for calculating this metric are described

tests/timeseries/_battery_pool/test_battery_pool.py

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,13 @@
2424
from frequenz.sdk.actor import ResamplerConfig
2525
from frequenz.sdk.actor.power_distributing import BatteryStatus
2626
from frequenz.sdk.microgrid.component import ComponentCategory
27+
from frequenz.sdk.timeseries import Quantity, Sample
2728
from frequenz.sdk.timeseries._quantities import Power
2829
from frequenz.sdk.timeseries.battery_pool import (
2930
BatteryPool,
3031
Bound,
3132
CapacityMetrics,
3233
PowerMetrics,
33-
SoCMetrics,
3434
)
3535
from frequenz.sdk.timeseries.battery_pool._metric_calculator import (
3636
battery_inverter_mapping,
@@ -670,31 +670,31 @@ async def run_soc_test(setup_args: SetupArgs) -> None:
670670
receiver.receive(), timeout=WAIT_FOR_COMPONENT_DATA_SEC + 0.2
671671
)
672672
now = datetime.now(tz=timezone.utc)
673-
expected = SoCMetrics(
673+
expected = Sample(
674674
timestamp=now,
675-
average_soc=10.0,
675+
value=Quantity(10.0),
676676
)
677677
compare_messages(msg, expected, WAIT_FOR_COMPONENT_DATA_SEC + 0.2)
678678

679679
batteries_in_pool = list(battery_pool.battery_ids)
680-
scenarios: list[Scenario[SoCMetrics]] = [
680+
scenarios: list[Scenario[Sample[Quantity]]] = [
681681
Scenario(
682682
batteries_in_pool[0],
683683
{"capacity": 150, "soc": 10},
684-
SoCMetrics(now, 2.5),
684+
Sample(now, Quantity(2.5)),
685685
),
686686
Scenario(
687687
batteries_in_pool[0],
688688
{
689689
"soc_lower_bound": 0.0,
690690
},
691-
SoCMetrics(now, 12.727272727272727),
691+
Sample(now, Quantity(12.727272727272727)),
692692
),
693693
# If NaN, then not include that battery in the metric.
694694
Scenario(
695695
batteries_in_pool[0],
696696
{"soc_upper_bound": float("NaN")},
697-
SoCMetrics(now, 10),
697+
Sample(now, Quantity(10.0)),
698698
),
699699
# All batteries are sending NaN, can't calculate SoC so we should send None
700700
Scenario(
@@ -705,7 +705,7 @@ async def run_soc_test(setup_args: SetupArgs) -> None:
705705
Scenario(
706706
batteries_in_pool[1],
707707
{"soc": 30},
708-
SoCMetrics(now, 10.0),
708+
Sample(now, Quantity(10.0)),
709709
),
710710
# Final metric didn't change, so nothing should be received.
711711
Scenario(
@@ -718,17 +718,17 @@ async def run_soc_test(setup_args: SetupArgs) -> None:
718718
Scenario(
719719
batteries_in_pool[1],
720720
{"capacity": 0},
721-
SoCMetrics(now, 0),
721+
Sample(now, Quantity(0.0)),
722722
),
723723
Scenario(
724724
batteries_in_pool[0],
725725
{"capacity": 50, "soc": 55.0},
726-
SoCMetrics(now, 50.0),
726+
Sample(now, Quantity(50.0)),
727727
),
728728
Scenario(
729729
batteries_in_pool[1],
730730
{"capacity": 150},
731-
SoCMetrics(now, 25.0),
731+
Sample(now, Quantity(25.0)),
732732
),
733733
]
734734

@@ -741,15 +741,15 @@ async def run_soc_test(setup_args: SetupArgs) -> None:
741741
all_batteries=all_batteries,
742742
batteries_in_pool=batteries_in_pool,
743743
waiting_time_sec=waiting_time_sec,
744-
all_pool_result=SoCMetrics(now, 25.0),
745-
only_first_battery_result=SoCMetrics(now, 50.0),
744+
all_pool_result=Sample(now, Quantity(25.0)),
745+
only_first_battery_result=Sample(now, Quantity(50.0)),
746746
)
747747

748748
# One battery stopped sending data.
749749
await streamer.stop_streaming(batteries_in_pool[1])
750750
await asyncio.sleep(MAX_BATTERY_DATA_AGE_SEC + 0.2)
751751
msg = await asyncio.wait_for(receiver.receive(), timeout=waiting_time_sec)
752-
compare_messages(msg, SoCMetrics(now, 50.0), 0.2)
752+
compare_messages(msg, Sample(now, Quantity(50.0)), 0.2)
753753

754754
# All batteries stopped sending data.
755755
await streamer.stop_streaming(batteries_in_pool[0])
@@ -761,7 +761,7 @@ async def run_soc_test(setup_args: SetupArgs) -> None:
761761
latest_data = streamer.get_current_component_data(batteries_in_pool[0])
762762
streamer.start_streaming(latest_data, sampling_rate=0.1)
763763
msg = await asyncio.wait_for(receiver.receive(), timeout=waiting_time_sec)
764-
compare_messages(msg, SoCMetrics(now, 50.0), 0.2)
764+
compare_messages(msg, Sample(now, Quantity(50.0)), 0.2)
765765

766766

767767
async def run_power_bounds_test( # pylint: disable=too-many-locals

0 commit comments

Comments
 (0)