Skip to content

Commit de4e062

Browse files
authored
Use Power instead of float in PowerDistributor's battery manager (#1214)
The PV manager and the EV Charger manager of the PowerDistributor are already using `Power` and not `float`.
2 parents 5100594 + 41d4543 commit de4e062

File tree

6 files changed

+1496
-581
lines changed

6 files changed

+1496
-581
lines changed

src/frequenz/sdk/microgrid/_power_distributing/_component_managers/_battery_manager.py

+62-45
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121
from frequenz.quantities import Power
2222
from typing_extensions import override
2323

24-
from ...._internal._math import is_close_to_zero
2524
from ... import connection_manager
2625
from .._component_pool_status_tracker import ComponentPoolStatusTracker
2726
from .._component_status import BatteryStatusTracker, ComponentPoolStatus
@@ -264,14 +263,12 @@ async def _distribute_power(
264263
Returns:
265264
Result from the microgrid API.
266265
"""
267-
distributed_power_value = (
268-
request.power.as_watts() - distribution.remaining_power
269-
)
270-
battery_distribution: dict[int, float] = {}
266+
distributed_power_value = request.power - distribution.remaining_power
267+
battery_distribution: dict[int, Power] = {}
271268
for inverter_id, dist in distribution.distribution.items():
272269
for battery_id in self._inv_bats_map[inverter_id]:
273270
battery_distribution[battery_id] = (
274-
battery_distribution.get(battery_id, 0.0) + dist
271+
battery_distribution.get(battery_id, Power.zero()) + dist
275272
)
276273
_logger.debug(
277274
"Distributing power %d between the batteries %s",
@@ -288,21 +285,19 @@ async def _distribute_power(
288285
succeed_batteries = set(battery_distribution.keys()) - failed_batteries
289286
response = PartialFailure(
290287
request=request,
291-
succeeded_power=Power.from_watts(
292-
distributed_power_value - failed_power
293-
),
288+
succeeded_power=distributed_power_value - failed_power,
294289
succeeded_components=succeed_batteries,
295-
failed_power=Power.from_watts(failed_power),
290+
failed_power=failed_power,
296291
failed_components=failed_batteries,
297-
excess_power=Power.from_watts(distribution.remaining_power),
292+
excess_power=distribution.remaining_power,
298293
)
299294
else:
300295
succeed_batteries = set(battery_distribution.keys())
301296
response = Success(
302297
request=request,
303-
succeeded_power=Power.from_watts(distributed_power_value),
298+
succeeded_power=distributed_power_value,
304299
succeeded_components=succeed_batteries,
305-
excess_power=Power.from_watts(distribution.remaining_power),
300+
excess_power=distribution.remaining_power,
306301
)
307302

308303
await asyncio.gather(
@@ -346,39 +341,59 @@ def _get_bounds(
346341
"""
347342
return PowerBounds(
348343
inclusion_lower=sum(
349-
max(
350-
battery.power_bounds.inclusion_lower,
351-
sum(
352-
inverter.active_power_inclusion_lower_bound
353-
for inverter in inverters
354-
),
355-
)
356-
for battery, inverters in pairs_data
344+
(
345+
max(
346+
battery.power_bounds.inclusion_lower,
347+
Power.from_watts(
348+
sum(
349+
inverter.active_power_inclusion_lower_bound
350+
for inverter in inverters
351+
)
352+
),
353+
)
354+
for battery, inverters in pairs_data
355+
),
356+
start=Power.zero(),
357357
),
358358
inclusion_upper=sum(
359-
min(
360-
battery.power_bounds.inclusion_upper,
361-
sum(
362-
inverter.active_power_inclusion_upper_bound
363-
for inverter in inverters
364-
),
365-
)
366-
for battery, inverters in pairs_data
359+
(
360+
min(
361+
battery.power_bounds.inclusion_upper,
362+
Power.from_watts(
363+
sum(
364+
inverter.active_power_inclusion_upper_bound
365+
for inverter in inverters
366+
)
367+
),
368+
)
369+
for battery, inverters in pairs_data
370+
),
371+
start=Power.zero(),
367372
),
368373
exclusion_lower=min(
369-
sum(battery.power_bounds.exclusion_lower for battery, _ in pairs_data),
370374
sum(
371-
inverter.active_power_exclusion_lower_bound
372-
for _, inverters in pairs_data
373-
for inverter in inverters
375+
(battery.power_bounds.exclusion_lower for battery, _ in pairs_data),
376+
start=Power.zero(),
377+
),
378+
Power.from_watts(
379+
sum(
380+
inverter.active_power_exclusion_lower_bound
381+
for _, inverters in pairs_data
382+
for inverter in inverters
383+
)
374384
),
375385
),
376386
exclusion_upper=max(
377-
sum(battery.power_bounds.exclusion_upper for battery, _ in pairs_data),
378387
sum(
379-
inverter.active_power_exclusion_upper_bound
380-
for _, inverters in pairs_data
381-
for inverter in inverters
388+
(battery.power_bounds.exclusion_upper for battery, _ in pairs_data),
389+
start=Power.zero(),
390+
),
391+
Power.from_watts(
392+
sum(
393+
inverter.active_power_exclusion_upper_bound
394+
for _, inverters in pairs_data
395+
for inverter in inverters
396+
)
382397
),
383398
),
384399
)
@@ -410,11 +425,11 @@ def _check_request(
410425

411426
bounds = self._get_bounds(pairs_data)
412427

413-
power = request.power.as_watts()
428+
power = request.power
414429

415430
# Zero power requests are always forwarded to the microgrid API, even if they
416431
# are outside the exclusion bounds.
417-
if is_close_to_zero(power):
432+
if power.isclose(Power.zero()):
418433
return None
419434

420435
if request.adjust_power:
@@ -599,7 +614,7 @@ def _get_power_distribution(
599614
unavailable_inv_ids = unavailable_inv_ids.union(inverter_ids)
600615

601616
result = self._distribution_algorithm.distribute_power(
602-
request.power.as_watts(), inv_bat_pairs
617+
request.power, inv_bat_pairs
603618
)
604619

605620
return result
@@ -608,7 +623,7 @@ async def _set_distributed_power(
608623
self,
609624
distribution: DistributionResult,
610625
timeout: timedelta,
611-
) -> tuple[float, set[int]]:
626+
) -> tuple[Power, set[int]]:
612627
"""Send distributed power to the inverters.
613628
614629
Args:
@@ -622,7 +637,9 @@ async def _set_distributed_power(
622637
api = connection_manager.get().api_client
623638

624639
tasks = {
625-
inverter_id: asyncio.create_task(api.set_power(inverter_id, power))
640+
inverter_id: asyncio.create_task(
641+
api.set_power(inverter_id, power.as_watts())
642+
)
626643
for inverter_id, power in distribution.distribution.items()
627644
}
628645

@@ -639,9 +656,9 @@ async def _set_distributed_power(
639656
def _parse_result(
640657
self,
641658
tasks: dict[int, asyncio.Task[None]],
642-
distribution: dict[int, float],
659+
distribution: dict[int, Power],
643660
request_timeout: timedelta,
644-
) -> tuple[float, set[int]]:
661+
) -> tuple[Power, set[int]]:
645662
"""Parse the results of `set_power` requests.
646663
647664
Check if any task has failed and determine the reason for failure.
@@ -658,7 +675,7 @@ def _parse_result(
658675
A tuple where the first element is the total failed power, and the second element is
659676
the set of batteries that failed.
660677
"""
661-
failed_power: float = 0.0
678+
failed_power: Power = Power.zero()
662679
failed_batteries: set[int] = set()
663680

664681
for inverter_id, aws in tasks.items():

0 commit comments

Comments
 (0)