Skip to content

Commit 9c51730

Browse files
committed
Replace uses of ComponentCategory with the new types
The new API client provides a mapping of `ComponentCategory` and `XxxType`s to Python classes. This commit updates most uses of component categories with these classes. This also includes some updates of imports for `Component` and `ComponentCategory` and some changes on specific component type, like `GridConnectionPoint`'s metadata. Finally, the component graph interface to get components was also updated to use types instead of categories, for which the API was slightly changed to better represent the filtering criteria. The keyword for arguments were changed from `component_ids` to `matching_ids` and `component_categories` to `matching_types`. Signed-off-by: Leandro Lucarella <[email protected]>
1 parent 1e5f079 commit 9c51730

37 files changed

+357
-515
lines changed

benchmarks/power_distribution/power_distributor.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313

1414
from frequenz.channels import Broadcast
1515
from frequenz.client.common.microgrid.components import ComponentId
16-
from frequenz.client.microgrid import Component, ComponentCategory
16+
from frequenz.client.microgrid.component import Battery
1717
from frequenz.quantities import Power
1818

1919
from frequenz.sdk import microgrid
@@ -116,8 +116,7 @@ async def run_test( # pylint: disable=too-many-locals
116116
battery_status_channel = Broadcast[ComponentPoolStatus](name="battery-status")
117117
power_result_channel = Broadcast[Result](name="power-result")
118118
async with PowerDistributingActor(
119-
component_category=ComponentCategory.BATTERY,
120-
component_type=None,
119+
component_type=Battery,
121120
requests_receiver=power_request_channel.new_receiver(),
122121
results_sender=power_result_channel.new_sender(),
123122
component_pool_status_sender=battery_status_channel.new_sender(),
@@ -143,8 +142,8 @@ async def run() -> None:
143142
ResamplerConfig2(resampling_period=timedelta(seconds=1.0)),
144143
)
145144

146-
all_batteries: set[Component] = connection_manager.get().component_graph.components(
147-
component_categories={ComponentCategory.BATTERY}
145+
all_batteries = connection_manager.get().component_graph.components(
146+
matching_types={Battery},
148147
)
149148
batteries_ids = {c.id for c in all_batteries}
150149
# Take some time to get data from components

src/frequenz/sdk/microgrid/_data_pipeline.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818

1919
from frequenz.channels import Broadcast, Sender
2020
from frequenz.client.common.microgrid.components import ComponentId
21-
from frequenz.client.microgrid import ComponentCategory, InverterType
21+
from frequenz.client.microgrid.component import Battery, EvCharger, SolarInverter
2222

2323
from frequenz.sdk.microgrid._power_managing._base_classes import Algorithm, DefaultPower
2424

@@ -105,23 +105,25 @@ def __init__(
105105
self._channel_registry,
106106
api_power_request_timeout=api_power_request_timeout,
107107
power_manager_algorithm=Algorithm.SHIFTING_MATRYOSHKA,
108-
component_category=ComponentCategory.BATTERY,
109108
default_power=DefaultPower.ZERO,
109+
component_class=Battery,
110110
)
111111
self._ev_power_wrapper = PowerWrapper(
112112
self._channel_registry,
113113
api_power_request_timeout=api_power_request_timeout,
114114
power_manager_algorithm=Algorithm.MATRYOSHKA,
115-
component_category=ComponentCategory.EV_CHARGER,
116115
default_power=DefaultPower.MAX,
116+
component_class=EvCharger,
117117
)
118118
self._pv_power_wrapper = PowerWrapper(
119119
self._channel_registry,
120120
api_power_request_timeout=api_power_request_timeout,
121121
power_manager_algorithm=Algorithm.MATRYOSHKA,
122-
component_category=ComponentCategory.INVERTER,
123-
component_type=InverterType.SOLAR,
124122
default_power=DefaultPower.MIN,
123+
# Using SolarInverter might be too specific, maybe we need to also pass
124+
# HybridInverter, see
125+
# https://github.com/frequenz-floss/frequenz-sdk-python/issues/1285
126+
component_class=SolarInverter,
125127
)
126128

127129
self._logical_meter: LogicalMeter | None = None

src/frequenz/sdk/microgrid/_old_component_data.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ def _check_category(cls, component_id: ComponentId) -> None:
160160
from .. import microgrid
161161

162162
components = microgrid.connection_manager.get().component_graph.components(
163-
filter_by_ids={component_id}
163+
matching_ids={component_id}
164164
)
165165
if not components:
166166
raise ValueError(f"Unable to find component with {component_id}")

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

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

1313
from frequenz.channels import LatestValueCache, Receiver, Sender
1414
from frequenz.client.common.microgrid.components import ComponentId
15-
from frequenz.client.microgrid import (
16-
ApiClientError,
17-
ComponentCategory,
18-
OperationOutOfRange,
19-
)
15+
from frequenz.client.microgrid import ApiClientError, OperationOutOfRange
16+
from frequenz.client.microgrid.component import Battery, Inverter
2017
from frequenz.quantities import Power
2118
from typing_extensions import override
2219

@@ -85,7 +82,9 @@ def _get_battery_inverter_mappings(
8582
inverters: set[ComponentId] = set(
8683
component.id
8784
for component in component_graph.predecessors(battery_id)
88-
if component.category == ComponentCategory.INVERTER
85+
# Using Inverter is way too general, see
86+
# https://github.com/frequenz-floss/frequenz-sdk-python/issues/1285
87+
if isinstance(component, Inverter)
8988
)
9089

9190
if len(inverters) == 0:
@@ -147,7 +146,7 @@ def __init__(
147146
self._results_sender = results_sender
148147
self._api_power_request_timeout = api_power_request_timeout
149148
self._batteries = connection_manager.get().component_graph.components(
150-
component_categories={ComponentCategory.BATTERY}
149+
matching_types={Battery}
151150
)
152151
self._battery_ids = {battery.id for battery in self._batteries}
153152

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

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,8 @@
1717
selected_from,
1818
)
1919
from frequenz.client.common.microgrid.components import ComponentId
20-
from frequenz.client.microgrid import (
21-
ApiClientError,
22-
ComponentCategory,
23-
MicrogridApiClient,
24-
)
20+
from frequenz.client.microgrid import ApiClientError, MicrogridApiClient
21+
from frequenz.client.microgrid.component import EvCharger
2522
from frequenz.quantities import Power, Voltage
2623
from typing_extensions import override
2724

@@ -115,7 +112,7 @@ def _get_ev_charger_ids(self) -> collections.abc.Set[ComponentId]:
115112
return {
116113
evc.id
117114
for evc in connection_manager.get().component_graph.components(
118-
component_categories={ComponentCategory.EV_CHARGER}
115+
matching_types={EvCharger}
119116
)
120117
}
121118

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

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,8 @@
1010

1111
from frequenz.channels import LatestValueCache, Sender
1212
from frequenz.client.common.microgrid.components import ComponentId
13-
from frequenz.client.microgrid import (
14-
ApiClientError,
15-
ComponentCategory,
16-
InverterType,
17-
)
13+
from frequenz.client.microgrid import ApiClientError
14+
from frequenz.client.microgrid.component import SolarInverter
1815
from frequenz.quantities import Power
1916
from typing_extensions import override
2017

@@ -258,7 +255,6 @@ def _get_pv_inverter_ids(self) -> collections.abc.Set[ComponentId]:
258255
return {
259256
inv.id
260257
for inv in connection_manager.get().component_graph.components(
261-
component_categories={ComponentCategory.INVERTER}
258+
matching_types={SolarInverter}
262259
)
263-
if inv.type == InverterType.SOLAR
264260
}

src/frequenz/sdk/microgrid/_power_distributing/_component_status/_battery_status_tracker.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,10 @@
2727
from frequenz.client.microgrid import (
2828
BatteryComponentState,
2929
BatteryRelayState,
30-
ComponentCategory,
3130
ErrorLevel,
3231
InverterComponentState,
3332
)
33+
from frequenz.client.microgrid.component import Inverter
3434
from typing_extensions import override
3535

3636
from frequenz.sdk._internal._asyncio import run_forever
@@ -486,7 +486,9 @@ def _find_adjacent_inverter_id(self, battery_id: ComponentId) -> ComponentId | N
486486
(
487487
comp.id
488488
for comp in graph.predecessors(battery_id)
489-
if comp.category == ComponentCategory.INVERTER
489+
# Using Inverter is way too general, see
490+
# https://github.com/frequenz-floss/frequenz-sdk-python/issues/1285
491+
if isinstance(comp, Inverter)
490492
),
491493
None,
492494
)

src/frequenz/sdk/microgrid/_power_distributing/power_distributing.py

Lines changed: 10 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,11 @@
1313
import asyncio
1414
import logging
1515
from datetime import datetime, timedelta
16+
from typing import assert_never
1617

1718
from frequenz.channels import Receiver, Sender
1819
from frequenz.client.common.microgrid.components import ComponentId
19-
from frequenz.client.microgrid import ComponentCategory, ComponentType, InverterType
20+
from frequenz.client.microgrid.component import Battery, EvCharger, SolarInverter
2021
from typing_extensions import override
2122

2223
from ...actor._actor import Actor
@@ -60,43 +61,31 @@ class PowerDistributingActor(Actor): # pylint: disable=too-many-instance-attrib
6061

6162
def __init__( # pylint: disable=too-many-arguments
6263
self,
64+
component_type: type[Battery | EvCharger | SolarInverter],
6365
requests_receiver: Receiver[Request],
6466
results_sender: Sender[Result],
6567
component_pool_status_sender: Sender[ComponentPoolStatus],
6668
*,
6769
api_power_request_timeout: timedelta,
68-
component_category: ComponentCategory,
69-
component_type: ComponentType | None = None,
7070
name: str | None = None,
7171
) -> None:
7272
"""Create actor instance.
7373
7474
Args:
75+
component_type: The class of the components that this actor is
76+
responsible for.
7577
requests_receiver: Receiver for receiving power requests from the power
7678
manager.
7779
results_sender: Sender for sending results to the power manager.
7880
component_pool_status_sender: Channel for sending information about which
7981
components are expected to be working.
8082
api_power_request_timeout: Timeout to use when making power requests to
8183
the microgrid API.
82-
component_category: The category of the components that this actor is
83-
responsible for.
84-
component_type: The type of the component of the given category that this
85-
actor is responsible for. This is used only when the component category
86-
is not enough to uniquely identify the component. For example, when the
87-
category is `ComponentCategory.INVERTER`, the type is needed to identify
88-
the inverter as a solar inverter or a battery inverter. This can be
89-
`None` when the component category is enough to uniquely identify the
90-
component.
9184
name: The name of the actor. If `None`, `str(id(self))` will be used. This
9285
is used mostly for debugging purposes.
93-
94-
Raises:
95-
ValueError: If the given component category is not supported.
9686
"""
9787
super().__init__(name=name)
98-
self._component_category = component_category
99-
self._component_type = component_type
88+
self._component_class = component_type
10089
self._requests_receiver = requests_receiver
10190
self._result_sender = results_sender
10291
self._api_power_request_timeout = api_power_request_timeout
@@ -114,25 +103,20 @@ def __init__( # pylint: disable=too-many-arguments
114103
"""
115104

116105
self._component_manager: ComponentManager
117-
if component_category == ComponentCategory.BATTERY:
106+
if issubclass(component_type, Battery):
118107
self._component_manager = BatteryManager(
119108
component_pool_status_sender, results_sender, api_power_request_timeout
120109
)
121-
elif component_category == ComponentCategory.EV_CHARGER:
110+
elif issubclass(component_type, EvCharger):
122111
self._component_manager = EVChargerManager(
123112
component_pool_status_sender, results_sender, api_power_request_timeout
124113
)
125-
elif (
126-
component_category == ComponentCategory.INVERTER
127-
and component_type == InverterType.SOLAR
128-
):
114+
elif issubclass(component_type, SolarInverter):
129115
self._component_manager = PVManager(
130116
component_pool_status_sender, results_sender, api_power_request_timeout
131117
)
132118
else:
133-
raise ValueError(
134-
f"PowerDistributor doesn't support controlling: {component_category}"
135-
)
119+
assert_never(component_type)
136120

137121
@override
138122
async def _run(self) -> None:

src/frequenz/sdk/microgrid/_power_managing/_power_managing_actor.py

Lines changed: 11 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
from frequenz.channels import Receiver, Sender, select, selected_from
1515
from frequenz.channels.timer import SkipMissedAndDrift, Timer
1616
from frequenz.client.common.microgrid.components import ComponentId
17-
from frequenz.client.microgrid import ComponentCategory, ComponentType, InverterType
17+
from frequenz.client.microgrid.component import Battery, EvCharger, SolarInverter
1818
from typing_extensions import override
1919

2020
from ..._internal._asyncio import run_forever
@@ -49,8 +49,7 @@ def __init__( # pylint: disable=too-many-arguments
4949
channel_registry: ChannelRegistry,
5050
algorithm: Algorithm,
5151
default_power: DefaultPower,
52-
component_category: ComponentCategory,
53-
component_type: ComponentType | None = None,
52+
component_class: type[Battery | EvCharger | SolarInverter],
5453
):
5554
"""Create a new instance of the power manager.
5655
@@ -64,19 +63,10 @@ def __init__( # pylint: disable=too-many-arguments
6463
channel_registry: The channel registry.
6564
algorithm: The power management algorithm to use.
6665
default_power: The default power to use for the components.
67-
component_category: The category of the component this power manager
68-
instance is going to support.
69-
component_type: The type of the component of the given category that this
70-
actor is responsible for. This is used only when the component category
71-
is not enough to uniquely identify the component. For example, when the
72-
category is `ComponentCategory.INVERTER`, the type is needed to identify
73-
the inverter as a solar inverter or a battery inverter. This can be
74-
`None` when the component category is enough to uniquely identify the
75-
component.
66+
component_class: The class of component this instance is going to support.
7667
"""
77-
self._component_category = component_category
78-
self._component_type = component_type
7968
self._default_power = default_power
69+
self._component_class = component_class
8070
self._bounds_subscription_receiver = bounds_subscription_receiver
8171
self._power_distributing_requests_sender = power_distributing_requests_sender
8272
self._power_distributing_results_receiver = power_distributing_results_receiver
@@ -153,39 +143,32 @@ def _add_system_bounds_tracker(self, component_ids: frozenset[ComponentId]) -> N
153143
154144
Args:
155145
component_ids: The component IDs for which to add a bounds tracker.
156-
157-
Raises:
158-
NotImplementedError: When the pool type is not supported.
159146
"""
160147
bounds_receiver: Receiver[SystemBounds]
161-
if self._component_category is ComponentCategory.BATTERY:
148+
if issubclass(self._component_class, Battery):
162149
battery_pool = _data_pipeline.new_battery_pool(
163150
priority=-sys.maxsize - 1, component_ids=component_ids
164151
)
165152
# pylint: disable-next=protected-access
166153
bounds_receiver = battery_pool._system_power_bounds.new_receiver()
167-
elif self._component_category is ComponentCategory.EV_CHARGER:
154+
elif issubclass(self._component_class, EvCharger):
168155
ev_charger_pool = _data_pipeline.new_ev_charger_pool(
169156
priority=-sys.maxsize - 1, component_ids=component_ids
170157
)
171158
# pylint: disable-next=protected-access
172159
bounds_receiver = ev_charger_pool._system_power_bounds.new_receiver()
173-
elif (
174-
self._component_category is ComponentCategory.INVERTER
175-
and self._component_type is InverterType.SOLAR
176-
):
160+
elif issubclass(self._component_class, SolarInverter):
177161
pv_pool = _data_pipeline.new_pv_pool(
178162
priority=-sys.maxsize - 1, component_ids=component_ids
179163
)
180164
# pylint: disable-next=protected-access
181165
bounds_receiver = pv_pool._system_power_bounds.new_receiver()
182166
else:
183-
err = (
184-
"PowerManagingActor: Unsupported component category: "
185-
f"{self._component_category}"
167+
_logger.error(
168+
"PowerManagingActor: Unsupported component class: %s",
169+
self._component_class.__name__,
186170
)
187-
_logger.error(err)
188-
raise NotImplementedError(err)
171+
assert_never(self._component_class)
189172

190173
self._system_bounds[component_ids] = SystemBounds(
191174
timestamp=datetime.now(tz=timezone.utc),

0 commit comments

Comments
 (0)