3939from ...power import DistributionAlgorithm , DistributionResult , InvBatPair
4040from ._battery_pool_status import BatteryPoolStatus , BatteryStatus
4141from .request import Request
42- from .result import Error , OutOfBound , PartialFailure , Result , Success
42+ from .result import Error , OutOfBound , PartialFailure , PowerBounds , Result , Success
4343
4444_logger = logging .getLogger (__name__ )
4545
@@ -226,6 +226,49 @@ def __init__(
226226 bat_id : None for bat_id , _ in self ._bat_inv_map .items ()
227227 }
228228
229+ def _get_bounds (
230+ self ,
231+ pairs_data : list [InvBatPair ],
232+ ) -> PowerBounds :
233+ """Get power bounds for given batteries.
234+
235+ Args:
236+ pairs_data: list of battery and adjacent inverter data pairs.
237+
238+ Returns:
239+ Power bounds for given batteries.
240+ """
241+ return PowerBounds (
242+ inclusion_lower = sum (
243+ max (
244+ battery .power_inclusion_lower_bound ,
245+ inverter .active_power_inclusion_lower_bound ,
246+ )
247+ for battery , inverter in pairs_data
248+ ),
249+ inclusion_upper = sum (
250+ min (
251+ battery .power_inclusion_upper_bound ,
252+ inverter .active_power_inclusion_upper_bound ,
253+ )
254+ for battery , inverter in pairs_data
255+ ),
256+ exclusion_lower = sum (
257+ min (
258+ battery .power_exclusion_lower_bound ,
259+ inverter .active_power_exclusion_lower_bound ,
260+ )
261+ for battery , inverter in pairs_data
262+ ),
263+ exclusion_upper = sum (
264+ max (
265+ battery .power_exclusion_upper_bound ,
266+ inverter .active_power_exclusion_upper_bound ,
267+ )
268+ for battery , inverter in pairs_data
269+ ),
270+ )
271+
229272 def _get_upper_bound (self , batteries : abc .Set [int ], include_broken : bool ) -> float :
230273 """Get total upper bound of power to be set for given batteries.
231274
@@ -307,11 +350,6 @@ async def run(self) -> None:
307350 await asyncio .sleep (self ._wait_for_data_sec )
308351
309352 async for request in self ._requests_receiver :
310- error = self ._check_request (request )
311- if error :
312- await self ._send_result (request .namespace , error )
313- continue
314-
315353 try :
316354 pairs_data : List [InvBatPair ] = self ._get_components_data (
317355 request .batteries , request .include_broken_batteries
@@ -329,6 +367,11 @@ async def run(self) -> None:
329367 )
330368 continue
331369
370+ error = self ._check_request (request , pairs_data )
371+ if error :
372+ await self ._send_result (request .namespace , error )
373+ continue
374+
332375 try :
333376 distribution = self ._get_power_distribution (request , pairs_data )
334377 except ValueError as err :
@@ -452,11 +495,16 @@ def _get_power_distribution(
452495
453496 return result
454497
455- def _check_request (self , request : Request ) -> Optional [Result ]:
498+ def _check_request (
499+ self ,
500+ request : Request ,
501+ pairs_data : List [InvBatPair ],
502+ ) -> Optional [Result ]:
456503 """Check whether the given request if correct.
457504
458505 Args:
459506 request: request to check
507+ pairs_data: list of battery and adjacent inverter data pairs.
460508
461509 Returns:
462510 Result for the user if the request is wrong, None otherwise.
@@ -472,19 +520,24 @@ def _check_request(self, request: Request) -> Optional[Result]:
472520 )
473521 return Error (request = request , msg = msg )
474522
475- if not request .adjust_power :
476- if request .power < 0 :
477- bound = self ._get_lower_bound (
478- request .batteries , request .include_broken_batteries
479- )
480- if request .power < bound :
481- return OutOfBound (request = request , bound = bound )
482- else :
483- bound = self ._get_upper_bound (
484- request .batteries , request .include_broken_batteries
485- )
486- if request .power > bound :
487- return OutOfBound (request = request , bound = bound )
523+ bounds = self ._get_bounds (pairs_data )
524+ if request .adjust_power :
525+ # Automatic power adjustments can only bring down the requested power down
526+ # to the inclusion bounds.
527+ #
528+ # If the requested power is in the exclusion bounds, it is NOT possible to
529+ # increase it so that it is outside the exclusion bounds.
530+ if bounds .exclusion_lower < request .power < bounds .exclusion_upper :
531+ return OutOfBound (request = request , bound = bounds )
532+ else :
533+ in_lower_range = (
534+ bounds .inclusion_lower <= request .power <= bounds .exclusion_lower
535+ )
536+ in_upper_range = (
537+ bounds .exclusion_upper <= request .power <= bounds .inclusion_upper
538+ )
539+ if not (in_lower_range or in_upper_range ):
540+ return OutOfBound (request = request , bound = bounds )
488541
489542 return None
490543
0 commit comments