77import uuid
88from collections import abc
99
10- from frequenz .channels import Sender
10+ from frequenz .channels import Broadcast , Receiver , Sender
1111from frequenz .client .microgrid import ComponentCategory
1212
13+ from ..._internal ._channels import ReceiverFetcher
1314from ...actor import ChannelRegistry , ComponentMetricRequest
15+ from ...actor .power_distributing import ComponentPoolStatus
1416from ...microgrid import connection_manager
17+ from .._base_types import SystemBounds
1518from .._quantities import Current , Power
1619from ..formula_engine import FormulaEngine , FormulaEngine3Phase
1720from ..formula_engine ._formula_engine_pool import FormulaEnginePool
2023 EVChargerPowerFormula ,
2124 FormulaGeneratorConfig ,
2225)
26+ from ._system_bounds_tracker import EVCSystemBoundsTracker
2327
2428
2529class EVChargerPoolError (Exception ):
@@ -41,10 +45,11 @@ class EVChargerPool:
4145 measurements of the EV Chargers in the pool.
4246 """
4347
44- def __init__ (
48+ def __init__ ( # pylint: disable=too-many-arguments
4549 self ,
4650 channel_registry : ChannelRegistry ,
4751 resampler_subscription_sender : Sender [ComponentMetricRequest ],
52+ status_receiver : Receiver [ComponentPoolStatus ],
4853 component_ids : abc .Set [int ] | None = None ,
4954 ) -> None :
5055 """Create an `EVChargerPool` instance.
@@ -59,6 +64,8 @@ def __init__(
5964 actor.
6065 resampler_subscription_sender: A sender for sending metric requests to the
6166 resampling actor.
67+ status_receiver: A receiver that streams the status of the EV Chargers in
68+ the pool.
6269 component_ids: An optional list of component_ids belonging to this pool. If
6370 not specified, IDs of all EV Chargers in the microgrid will be fetched
6471 from the component graph.
@@ -67,6 +74,7 @@ def __init__(
6774 self ._resampler_subscription_sender : Sender [ComponentMetricRequest ] = (
6875 resampler_subscription_sender
6976 )
77+ self ._status_receiver : Receiver [ComponentPoolStatus ] = status_receiver
7078 self ._component_ids : abc .Set [int ] = set ()
7179 if component_ids is not None :
7280 self ._component_ids = component_ids
@@ -85,6 +93,14 @@ def __init__(
8593 self ._resampler_subscription_sender ,
8694 )
8795
96+ self ._bounds_channel : Broadcast [SystemBounds ] = Broadcast (
97+ name = f"System Bounds for EV Chargers: { component_ids } "
98+ )
99+ self ._bounds_tracker : EVCSystemBoundsTracker = EVCSystemBoundsTracker (
100+ self .component_ids , self ._status_receiver , self ._bounds_channel .new_sender ()
101+ )
102+ self ._bounds_tracker .start ()
103+
88104 @property
89105 def component_ids (self ) -> abc .Set [int ]:
90106 """Return component IDs of all EV Chargers managed by this EVChargerPool.
@@ -147,3 +163,8 @@ def power(self) -> FormulaEngine[Power]:
147163 async def stop (self ) -> None :
148164 """Stop all tasks and channels owned by the EVChargerPool."""
149165 await self ._formula_pool .stop ()
166+
167+ @property
168+ def _system_power_bounds (self ) -> ReceiverFetcher [SystemBounds ]:
169+ """Return a receiver for the system power bounds."""
170+ return self ._bounds_channel
0 commit comments