Skip to content

Commit 5e71f34

Browse files
committed
Add ComponentGraph wrapper adding back the component type checks
That's how it used to be before the rust component graph was introduced. Signed-off-by: Sahas Subramanian <[email protected]>
1 parent ca12ecb commit 5e71f34

File tree

3 files changed

+182
-12
lines changed

3 files changed

+182
-12
lines changed

pyproject.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,8 @@ dependencies = [
2929
# Make sure to update the mkdocs.yml file when
3030
# changing the version
3131
# (plugins.mkdocstrings.handlers.python.import)
32-
"frequenz-client-microgrid >= 0.18.0, < 0.19.0",
33-
"frequenz-microgrid-component-graph >= 0.2.0, < 0.3",
32+
"frequenz-client-microgrid >= 0.18.1, < 0.19.0",
33+
"frequenz-microgrid-component-graph >= 0.3.2, < 0.4",
3434
"frequenz-client-common >= 0.3.6, < 0.4.0",
3535
"frequenz-channels >= 1.6.1, < 2.0.0",
3636
"frequenz-quantities[marshmallow] >= 1.0.0, < 2.0.0",
Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
# License: MIT
2+
# Copyright © 2025 Frequenz Energy-as-a-Service GmbH
3+
4+
"""Component graph representation for a microgrid."""
5+
6+
from frequenz.client.common.microgrid.components import ComponentId
7+
from frequenz.client.microgrid.component import (
8+
BatteryInverter,
9+
Chp,
10+
Component,
11+
ComponentConnection,
12+
EvCharger,
13+
SolarInverter,
14+
)
15+
from frequenz.microgrid_component_graph import ComponentGraph as BaseComponentGraph
16+
from typing_extensions import override
17+
18+
19+
class ComponentGraph(BaseComponentGraph[Component, ComponentConnection, ComponentId]):
20+
"""A representation of a microgrid's component graph."""
21+
22+
def is_pv_inverter(self, component: Component) -> bool:
23+
"""Check if the specified component is a PV inverter.
24+
25+
Args:
26+
component: The component to check.
27+
28+
Returns:
29+
Whether the specified component is a PV inverter.
30+
"""
31+
return isinstance(component, SolarInverter)
32+
33+
def is_pv_chain(self, component: Component) -> bool:
34+
"""Check if the specified component is part of a PV chain.
35+
36+
A component is part of a PV chain if it is either a PV inverter or a PV
37+
meter.
38+
39+
Args:
40+
component: The component to check.
41+
42+
Returns:
43+
Whether the specified component is part of a PV chain.
44+
"""
45+
return self.is_pv_inverter(component) or self.is_pv_meter(component)
46+
47+
@override
48+
def is_pv_meter(self, component: Component | ComponentId) -> bool:
49+
"""Check if the specified component is a PV meter.
50+
51+
Args:
52+
component: The component or component ID to check.
53+
54+
Returns:
55+
Whether the specified component is a PV meter.
56+
"""
57+
if isinstance(component, Component):
58+
return super().is_pv_meter(component.id)
59+
return super().is_pv_meter(component)
60+
61+
def is_ev_charger(self, component: Component) -> bool:
62+
"""Check if the specified component is an EV charger.
63+
64+
Args:
65+
component: The component to check.
66+
67+
Returns:
68+
Whether the specified component is an EV charger.
69+
"""
70+
return isinstance(component, EvCharger)
71+
72+
def is_ev_charger_chain(self, component: Component) -> bool:
73+
"""Check if the specified component is part of an EV charger chain.
74+
75+
A component is part of an EV charger chain if it is either an EV charger or an
76+
EV charger meter.
77+
78+
Args:
79+
component: The component to check.
80+
81+
Returns:
82+
Whether the specified component is part of an EV charger chain.
83+
"""
84+
return self.is_ev_charger(component) or self.is_ev_charger_meter(component)
85+
86+
@override
87+
def is_ev_charger_meter(self, component: Component | ComponentId) -> bool:
88+
"""Check if the specified component is an EV charger meter.
89+
90+
Args:
91+
component: The component or component ID to check.
92+
93+
Returns:
94+
Whether the specified component is an EV charger meter.
95+
"""
96+
if isinstance(component, Component):
97+
return super().is_ev_charger_meter(component.id)
98+
return super().is_ev_charger_meter(component)
99+
100+
def is_battery_inverter(self, component: Component) -> bool:
101+
"""Check if the specified component is a battery inverter.
102+
103+
Args:
104+
component: The component to check.
105+
106+
Returns:
107+
Whether the specified component is a battery inverter.
108+
"""
109+
return isinstance(component, BatteryInverter)
110+
111+
def is_battery_chain(self, component: Component) -> bool:
112+
"""Check if the specified component is part of a battery chain.
113+
114+
A component is part of a battery chain if it is either a battery inverter or a
115+
battery meter.
116+
117+
Args:
118+
component: The component to check.
119+
120+
Returns:
121+
Whether the specified component is part of a battery chain.
122+
"""
123+
return self.is_battery_inverter(component) or self.is_battery_meter(component)
124+
125+
@override
126+
def is_battery_meter(self, component: Component | ComponentId) -> bool:
127+
"""Check if the specified component is a battery meter.
128+
129+
Args:
130+
component: The component or component ID to check.
131+
132+
Returns:
133+
Whether the specified component is a battery meter.
134+
"""
135+
if isinstance(component, Component):
136+
return super().is_battery_meter(component.id)
137+
return super().is_battery_meter(component)
138+
139+
def is_chp(self, component: Component) -> bool:
140+
"""Check if the specified component is a CHP.
141+
142+
Args:
143+
component: The component to check.
144+
145+
Returns:
146+
Whether the specified component is a CHP.
147+
"""
148+
return isinstance(component, Chp)
149+
150+
def is_chp_chain(self, component: Component) -> bool:
151+
"""Check if the specified component is part of a CHP chain.
152+
153+
A component is part of a CHP chain if it is either a CHP or a CHP meter.
154+
155+
Args:
156+
component: The component to check.
157+
158+
Returns:
159+
Whether the specified component is part of a CHP chain.
160+
"""
161+
return self.is_chp(component) or self.is_chp_meter(component)
162+
163+
@override
164+
def is_chp_meter(self, component: Component | ComponentId) -> bool:
165+
"""Check if the specified component is a CHP meter.
166+
167+
Args:
168+
component: The component or component ID to check.
169+
170+
Returns:
171+
Whether the specified component is a CHP meter.
172+
"""
173+
if isinstance(component, Component):
174+
return super().is_chp_meter(component.id)
175+
return super().is_chp_meter(component)

src/frequenz/sdk/microgrid/connection_manager.py

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,13 @@
1313
from abc import ABC, abstractmethod
1414

1515
from frequenz.client.common.microgrid import MicrogridId
16-
from frequenz.client.common.microgrid.components import ComponentId
1716
from frequenz.client.microgrid import (
1817
Location,
1918
MicrogridApiClient,
2019
MicrogridInfo,
2120
)
22-
from frequenz.client.microgrid.component import Component, ComponentConnection
23-
from frequenz.microgrid_component_graph import ComponentGraph
21+
22+
from .component_graph import ComponentGraph
2423

2524
_logger = logging.getLogger(__name__)
2625

@@ -59,7 +58,7 @@ def api_client(self) -> MicrogridApiClient:
5958
@abstractmethod
6059
def component_graph(
6160
self,
62-
) -> ComponentGraph[Component, ComponentConnection, ComponentId]:
61+
) -> ComponentGraph:
6362
"""Get component graph.
6463
6564
Returns:
@@ -109,9 +108,7 @@ def __init__(self, server_url: str) -> None:
109108
self._client = MicrogridApiClient(server_url)
110109
# To create graph from the API client we need await.
111110
# So create empty graph here, and update it in `run` method.
112-
self._graph: (
113-
ComponentGraph[Component, ComponentConnection, ComponentId] | None
114-
) = None
111+
self._graph: ComponentGraph | None = None
115112

116113
self._microgrid: MicrogridInfo
117114
"""The microgrid information."""
@@ -140,9 +137,7 @@ def location(self) -> Location | None:
140137
return self._microgrid.location
141138

142139
@property
143-
def component_graph(
144-
self,
145-
) -> ComponentGraph[Component, ComponentConnection, ComponentId]:
140+
def component_graph(self) -> ComponentGraph:
146141
"""Get component graph.
147142
148143
Returns:

0 commit comments

Comments
 (0)