1616from . import _bounds
1717
1818if typing .TYPE_CHECKING :
19- from ...timeseries .battery_pool import PowerMetrics
19+ from ...timeseries ._base_types import SystemBounds
2020 from .. import power_distributing
2121
2222
@@ -27,8 +27,8 @@ class ReportRequest:
2727 source_id : str
2828 """The source ID of the actor sending the request."""
2929
30- battery_ids : frozenset [int ]
31- """The battery IDs to report on."""
30+ component_ids : frozenset [int ]
31+ """The component IDs to report on."""
3232
3333 priority : int
3434 """The priority of the actor ."""
@@ -40,15 +40,67 @@ def get_channel_name(self) -> str:
4040 The channel name to use to identify the corresponding report channel
4141 from the channel registry.
4242 """
43- return f"power_manager.report.{ self .battery_ids = } .{ self .priority = } "
43+ return f"power_manager.report.{ self .component_ids = } .{ self .priority = } "
44+
45+
46+ class Report (typing .Protocol ):
47+ """Current PowerManager report for a set of components.
48+
49+ This protocol can be specialized by different component pools to provide more
50+ specific details and documentation for the reports.
51+ """
52+
53+ @property
54+ def bounds (self ) -> timeseries .Bounds [Power ] | None :
55+ """The bounds for the components.
56+
57+ These bounds are adjusted to any restrictions placed by actors with higher
58+ priorities.
59+
60+ There might be exclusion zones within these bounds. If necessary, the
61+ `adjust_to_bounds` method may be used to check if a desired power value fits the
62+ bounds, or to get the closest possible power values that do fit the bounds.
63+ """
64+
65+ @abc .abstractmethod
66+ def adjust_to_bounds (self , power : Power ) -> tuple [Power | None , Power | None ]:
67+ """Adjust a power value to the bounds.
68+
69+ This method can be used to adjust a desired power value to the power bounds
70+ available to the actor.
71+
72+ If the given power value falls within the usable bounds, it will be returned
73+ unchanged.
74+
75+ If it falls outside the usable bounds, the closest possible value on the
76+ corresponding side will be returned. For example, if the given power is lower
77+ than the lowest usable power, only the lowest usable power will be returned, and
78+ similarly for the highest usable power.
79+
80+ If the given power falls within an exclusion zone that's contained within the
81+ usable bounds, the closest possible power values on both sides will be returned.
82+
83+ !!! note
84+ It is completely optional to use this method to adjust power values before
85+ proposing them, because the PowerManager will do this automatically. This
86+ method is provided for convenience, and for granular control when there are
87+ two possible power values, both of which fall within the available bounds.
88+
89+ Args:
90+ power: The power value to adjust.
91+
92+ Returns:
93+ A tuple of the closest power values to the desired power that fall within
94+ the available bounds for the actor.
95+ """
4496
4597
4698@dataclasses .dataclass (frozen = True , kw_only = True )
47- class Report :
48- """Current PowerManager report for a set of batteries ."""
99+ class _Report ( Report ) :
100+ """Current PowerManager report for a set of components ."""
49101
50102 target_power : Power | None
51- """The currently set power for the batteries ."""
103+ """The currently set power for the components ."""
52104
53105 distribution_result : power_distributing .Result | None
54106 """The result of the last power distribution.
@@ -57,14 +109,14 @@ class Report:
57109 """
58110
59111 _inclusion_bounds : timeseries .Bounds [Power ] | None
60- """The available inclusion bounds for the batteries , for the actor's priority.
112+ """The available inclusion bounds for the components , for the actor's priority.
61113
62114 These bounds are adjusted to any restrictions placed by actors with higher
63115 priorities.
64116 """
65117
66118 _exclusion_bounds : timeseries .Bounds [Power ] | None
67- """The exclusion bounds for the batteries .
119+ """The exclusion bounds for the components .
68120
69121 The power manager doesn't manage exclusion bounds, so these are aggregations of
70122 values reported by the microgrid API.
@@ -75,15 +127,14 @@ class Report:
75127
76128 @property
77129 def bounds (self ) -> timeseries .Bounds [Power ] | None :
78- """The bounds for the batteries .
130+ """The bounds for the components .
79131
80132 These bounds are adjusted to any restrictions placed by actors with higher
81133 priorities.
82134
83135 There might be exclusion zones within these bounds. If necessary, the
84- [`adjust_to_bounds`][frequenz.sdk.timeseries.battery_pool.Report.adjust_to_bounds]
85- method may be used to check if a desired power value fits the bounds, or to get
86- the closest possible power values that do fit the bounds.
136+ `adjust_to_bounds` method may be used to check if a desired power value fits the
137+ bounds, or to get the closest possible power values that do fit the bounds.
87138 """
88139 return self ._inclusion_bounds
89140
@@ -106,29 +157,9 @@ def adjust_to_bounds(self, power: Power) -> tuple[Power | None, Power | None]:
106157
107158 !!! note
108159 It is completely optional to use this method to adjust power values before
109- proposing them through the battery pool, because the battery pool will do
110- this automatically. This method is provided for convenience, and for
111- granular control when there are two possible power values, both of which
112- fall within the available bounds.
113-
114- Example:
115- ```python
116- from frequenz.sdk import microgrid
117-
118- power_status_rx = microgrid.battery_pool().power_status.new_receiver()
119- power_status = await power_status_rx.receive()
120- desired_power = Power.from_watts(1000.0)
121-
122- match power_status.adjust_to_bounds(desired_power):
123- case (power, _) if power == desired_power:
124- print("Desired power is available.")
125- case (None, power) | (power, None) if power:
126- print(f"Closest available power is {power}.")
127- case (lower, upper) if lower and upper:
128- print(f"Two options {lower}, {upper} to propose to battery pool.")
129- case (None, None):
130- print("No available power")
131- ```
160+ proposing them, because the PowerManager will do this automatically. This
161+ method is provided for convenience, and for granular control when there are
162+ two possible power values, both of which fall within the available bounds.
132163
133164 Args:
134165 power: The power value to adjust.
@@ -150,13 +181,13 @@ def adjust_to_bounds(self, power: Power) -> tuple[Power | None, Power | None]:
150181
151182@dataclasses .dataclass (frozen = True , kw_only = True )
152183class Proposal :
153- """A proposal for a battery to be charged or discharged."""
184+ """A proposal for a set of components to be charged or discharged."""
154185
155186 source_id : str
156187 """The source ID of the actor sending the request."""
157188
158189 preferred_power : Power | None
159- """The preferred power to be distributed to the batteries .
190+ """The preferred power to be distributed to the components .
160191
161192 If `None`, the preferred power of higher priority actors will get precedence.
162193 """
@@ -166,12 +197,12 @@ class Proposal:
166197
167198 These bounds will apply to actors with a lower priority, and can be overridden by
168199 bounds from actors with a higher priority. If None, the power bounds will be set to
169- the maximum power of the batteries in the pool. This is currently an experimental
200+ the maximum power of the components in the pool. This is currently an experimental
170201 feature.
171202 """
172203
173- battery_ids : frozenset [int ]
174- """The battery IDs to distribute the power to."""
204+ component_ids : frozenset [int ]
205+ """The component IDs to distribute the power to."""
175206
176207 priority : int
177208 """The priority of the actor sending the proposal."""
@@ -207,23 +238,23 @@ class BaseAlgorithm(abc.ABC):
207238 @abc .abstractmethod
208239 def calculate_target_power (
209240 self ,
210- battery_ids : frozenset [int ],
241+ component_ids : frozenset [int ],
211242 proposal : Proposal | None ,
212- system_bounds : PowerMetrics ,
243+ system_bounds : SystemBounds ,
213244 must_return_power : bool = False ,
214245 ) -> Power | None :
215- """Calculate and return the target power for the given batteries .
246+ """Calculate and return the target power for the given components .
216247
217248 Args:
218- battery_ids : The battery IDs to calculate the target power for.
249+ component_ids : The component IDs to calculate the target power for.
219250 proposal: If given, the proposal to added to the bucket, before the target
220251 power is calculated.
221- system_bounds: The system bounds for the batteries in the proposal.
252+ system_bounds: The system bounds for the components in the proposal.
222253 must_return_power: If `True`, the algorithm must return a target power,
223254 even if it hasn't changed since the last call.
224255
225256 Returns:
226- The new target power for the batteries , or `None` if the target power
257+ The new target power for the components , or `None` if the target power
227258 didn't change.
228259 """
229260
@@ -232,19 +263,19 @@ def calculate_target_power(
232263 @abc .abstractmethod
233264 def get_status (
234265 self ,
235- battery_ids : frozenset [int ],
266+ component_ids : frozenset [int ],
236267 priority : int ,
237- system_bounds : PowerMetrics ,
268+ system_bounds : SystemBounds ,
238269 distribution_result : power_distributing .Result | None ,
239- ) -> Report :
240- """Get the bounds for a set of batteries , for the given priority.
270+ ) -> _Report :
271+ """Get the bounds for a set of components , for the given priority.
241272
242273 Args:
243- battery_ids : The IDs of the batteries to get the bounds for.
274+ component_ids : The IDs of the components to get the bounds for.
244275 priority: The priority of the actor for which the bounds are requested.
245- system_bounds: The system bounds for the batteries .
276+ system_bounds: The system bounds for the components .
246277 distribution_result: The result of the last power distribution.
247278
248279 Returns:
249- The bounds for the batteries .
280+ The bounds for the components .
250281 """
0 commit comments