Skip to content

Commit a829a8d

Browse files
committed
Distinguish between grid meters and {pv/ev/battery/chp} meters
It was possible to have a grid meter identified as a pv/ev/battery/chp meter for specific component graph configurations. But grid meters might also be measuring site consumption, so the above use was incorrect. This is fixed by adding a `is_grid_meter` check to the component graph `is_{pv/ev/battery/chp}_meter` methods. Signed-off-by: Sahas Subramanian <[email protected]>
1 parent 16bb5cb commit a829a8d

File tree

1 file changed

+44
-0
lines changed

1 file changed

+44
-0
lines changed

src/frequenz/sdk/microgrid/component_graph.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,20 @@ def successors(self, component_id: int) -> set[Component]:
120120
KeyError: if the specified `component_id` is not in the graph
121121
"""
122122

123+
@abstractmethod
124+
def is_grid_meter(self, component: Component) -> bool:
125+
"""Check if the specified component is a grid meter.
126+
127+
This is done by checking if the component is the only successor to the `Grid`
128+
component.
129+
130+
Args:
131+
component: component to check.
132+
133+
Returns:
134+
Whether the specified component is a grid meter.
135+
"""
136+
123137
@abstractmethod
124138
def is_pv_inverter(self, component: Component) -> bool:
125139
"""Check if the specified component is a PV inverter.
@@ -567,6 +581,32 @@ def validate(self) -> None:
567581
self._validate_intermediary_components()
568582
self._validate_leaf_components()
569583

584+
def is_grid_meter(self, component: Component) -> bool:
585+
"""Check if the specified component is a grid meter.
586+
587+
This is done by checking if the component is the only successor to the `Grid`
588+
component.
589+
590+
Args:
591+
component: component to check.
592+
593+
Returns:
594+
Whether the specified component is a grid meter.
595+
"""
596+
if component.category != ComponentCategory.METER:
597+
return False
598+
599+
predecessors = self.predecessors(component.component_id)
600+
if len(predecessors) != 1:
601+
return False
602+
603+
predecessor = next(iter(predecessors))
604+
if predecessor.category != ComponentCategory.GRID:
605+
return False
606+
607+
grid_successors = self.successors(predecessor.component_id)
608+
return len(grid_successors) == 1
609+
570610
def is_pv_inverter(self, component: Component) -> bool:
571611
"""Check if the specified component is a PV inverter.
572612
@@ -596,6 +636,7 @@ def is_pv_meter(self, component: Component) -> bool:
596636
successors = self.successors(component.component_id)
597637
return (
598638
component.category == ComponentCategory.METER
639+
and not self.is_grid_meter(component)
599640
and len(successors) > 0
600641
and all(
601642
self.is_pv_inverter(successor)
@@ -643,6 +684,7 @@ def is_ev_charger_meter(self, component: Component) -> bool:
643684
successors = self.successors(component.component_id)
644685
return (
645686
component.category == ComponentCategory.METER
687+
and not self.is_grid_meter(component)
646688
and len(successors) > 0
647689
and all(self.is_ev_charger(successor) for successor in successors)
648690
)
@@ -690,6 +732,7 @@ def is_battery_meter(self, component: Component) -> bool:
690732
successors = self.successors(component.component_id)
691733
return (
692734
component.category == ComponentCategory.METER
735+
and not self.is_grid_meter(component)
693736
and len(successors) > 0
694737
and all(self.is_battery_inverter(successor) for successor in successors)
695738
)
@@ -734,6 +777,7 @@ def is_chp_meter(self, component: Component) -> bool:
734777
successors = self.successors(component.component_id)
735778
return (
736779
component.category == ComponentCategory.METER
780+
and not self.is_grid_meter(component)
737781
and len(successors) > 0
738782
and all(self.is_chp(successor) for successor in successors)
739783
)

0 commit comments

Comments
 (0)