Skip to content

Commit 56f5263

Browse files
committed
Use new component states and state snapshots
The new state snapshots in the v0.18 client provide errors and warnings using a different structure, so we need to account for that. State code were also unified and there is no more specific enums for cable state and other component-specific states, all states are part of the `ComponentStateCode` enum and the component data can have many state codes in it, while before it contained only one. In previous versions EV chargers only used one `PLUGGED` or `LOCKED` status but now the cable status was split in 2 connector ends: station and EV, so now all combinations of those need to be accounted for. This might change again on the API side as it ended up a bit messy. Also the old component data wrappers now can't be frozen because the `ComponentData` class is not frozen (this is to allow parsing from the new telemetry messages easier for phases). Signed-off-by: Leandro Lucarella <[email protected]>
1 parent ceba590 commit 56f5263

File tree

11 files changed

+219
-234
lines changed

11 files changed

+219
-234
lines changed

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

Lines changed: 37 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,7 @@
2424
from frequenz.channels import Receiver, Sender, select, selected_from
2525
from frequenz.channels.timer import SkipMissedAndDrift, Timer
2626
from frequenz.client.common.microgrid.components import ComponentId
27-
from frequenz.client.microgrid import (
28-
BatteryComponentState,
29-
BatteryRelayState,
30-
ErrorLevel,
31-
InverterComponentState,
32-
)
33-
from frequenz.client.microgrid.component import Inverter
27+
from frequenz.client.microgrid.component import ComponentStateCode, Inverter
3428
from typing_extensions import override
3529

3630
from frequenz.sdk._internal._asyncio import run_forever
@@ -70,28 +64,34 @@ class BatteryStatusTracker(ComponentStatusTracker, BackgroundService):
7064
Status updates are sent out only when there is a status change.
7165
"""
7266

73-
_battery_valid_relay: set[BatteryRelayState] = {BatteryRelayState.CLOSED}
67+
_battery_valid_relay: frozenset[ComponentStateCode] = frozenset(
68+
[ComponentStateCode.RELAY_CLOSED]
69+
)
7470
"""The list of valid relay states of a battery.
7571
7672
A working battery in any other battery relay state will be reported as failing.
7773
"""
7874

79-
_battery_valid_state: set[BatteryComponentState] = {
80-
BatteryComponentState.IDLE,
81-
BatteryComponentState.CHARGING,
82-
BatteryComponentState.DISCHARGING,
83-
}
75+
_battery_valid_state: frozenset[ComponentStateCode] = frozenset(
76+
[
77+
ComponentStateCode.READY,
78+
ComponentStateCode.CHARGING,
79+
ComponentStateCode.DISCHARGING,
80+
]
81+
)
8482
"""The list of valid states of a battery.
8583
8684
A working battery in any other battery state will be reported as failing.
8785
"""
8886

89-
_inverter_valid_state: set[InverterComponentState] = {
90-
InverterComponentState.STANDBY,
91-
InverterComponentState.IDLE,
92-
InverterComponentState.CHARGING,
93-
InverterComponentState.DISCHARGING,
94-
}
87+
_inverter_valid_state: frozenset[ComponentStateCode] = frozenset(
88+
[
89+
ComponentStateCode.STANDBY,
90+
ComponentStateCode.READY,
91+
ComponentStateCode.CHARGING,
92+
ComponentStateCode.DISCHARGING,
93+
]
94+
)
9595
"""The list of valid states of an inverter.
9696
9797
A working inverter in any other inverter state will be reported as failing.
@@ -371,15 +371,13 @@ def _no_critical_error(self, msg: BatteryData | InverterData) -> bool:
371371
Returns:
372372
True if message has no critical error, False otherwise.
373373
"""
374-
critical = ErrorLevel.CRITICAL
375-
critical_err = next((err for err in msg.errors if err.level == critical), None)
376-
if critical_err is not None:
374+
if msg.errors:
377375
last_status = self._last_status # pylint: disable=protected-access
378376
if last_status == ComponentStatusEnum.WORKING:
379377
_logger.warning(
380-
"Component %d has critical error: %s",
378+
"Component %d has errors: %s",
381379
msg.component_id,
382-
str(critical_err),
380+
str(msg.errors),
383381
)
384382
return False
385383
return True
@@ -394,14 +392,15 @@ def _is_inverter_state_correct(self, msg: InverterData) -> bool:
394392
True if inverter is in correct state. False otherwise.
395393
"""
396394
# Component state is not exposed to the user.
397-
state = msg.component_state
395+
component_states = msg.states
398396
# pylint: disable-next=protected-access
399-
if state not in BatteryStatusTracker._inverter_valid_state:
397+
valid_states = BatteryStatusTracker._inverter_valid_state
398+
if not component_states & valid_states:
400399
if self._last_status == ComponentStatusEnum.WORKING:
401400
_logger.warning(
402-
"Inverter %d has invalid state: %s",
401+
"Inverter %d has invalid states: %s",
403402
msg.component_id,
404-
state.name,
403+
msg.states,
405404
)
406405
return False
407406
return True
@@ -416,25 +415,27 @@ def _is_battery_state_correct(self, msg: BatteryData) -> bool:
416415
True if battery is in correct state. False otherwise.
417416
"""
418417
# Component state is not exposed to the user.
419-
state = msg.component_state
418+
component_states = msg.states
420419
# pylint: disable-next=protected-access
421-
if state not in BatteryStatusTracker._battery_valid_state:
420+
valid_states = BatteryStatusTracker._battery_valid_state
421+
if not component_states & valid_states:
422422
if self._last_status == ComponentStatusEnum.WORKING:
423423
_logger.warning(
424-
"Battery %d has invalid state: %s",
424+
"Battery %d has invalid states: %s, expected: %s",
425425
self.battery_id,
426-
state.name,
426+
msg.states,
427+
valid_states,
427428
)
428429
return False
429430

430431
# Component state is not exposed to the user.
431-
relay_state = msg.relay_state
432-
if relay_state not in BatteryStatusTracker._battery_valid_relay:
432+
if not msg.states & BatteryStatusTracker._battery_valid_relay:
433433
if self._last_status == ComponentStatusEnum.WORKING:
434434
_logger.warning(
435-
"Battery %d has invalid relay state: %s",
435+
"Battery %d has invalid states: %s, expected: %s",
436436
self.battery_id,
437-
relay_state.name,
437+
msg.states,
438+
BatteryStatusTracker._battery_valid_relay,
438439
)
439440
return False
440441
return True

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

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,7 @@
1111
from frequenz.channels import Receiver, Sender, select, selected_from
1212
from frequenz.channels.timer import SkipMissedAndDrift, Timer
1313
from frequenz.client.common.microgrid.components import ComponentId
14-
from frequenz.client.microgrid import (
15-
EVChargerCableState,
16-
EVChargerComponentState,
17-
)
14+
from frequenz.client.microgrid.component import ComponentStateCode
1815
from typing_extensions import override
1916

2017
from ...._internal._asyncio import run_forever
@@ -87,14 +84,16 @@ def start(self) -> None:
8784

8885
def _is_working(self, ev_data: EVChargerData) -> bool:
8986
"""Return whether the given data indicates that the component is working."""
90-
return ev_data.cable_state in (
91-
EVChargerCableState.EV_PLUGGED,
92-
EVChargerCableState.EV_LOCKED,
93-
) and ev_data.component_state in (
94-
EVChargerComponentState.READY,
95-
EVChargerComponentState.CHARGING,
96-
EVChargerComponentState.DISCHARGING,
87+
is_connected = ev_data.is_ev_connected()
88+
is_ok = bool(
89+
{
90+
ComponentStateCode.READY,
91+
ComponentStateCode.CHARGING,
92+
ComponentStateCode.DISCHARGING,
93+
}
94+
& ev_data.states
9795
)
96+
return is_connected and is_ok
9897

9998
def _is_stale(self, ev_data: EVChargerData) -> bool:
10099
"""Return whether the given data is stale."""
@@ -123,11 +122,9 @@ def _handle_ev_data(self, ev_data: EVChargerData) -> ComponentStatusEnum:
123122

124123
if self._last_status == ComponentStatusEnum.WORKING:
125124
_logger.warning(
126-
"EV charger %s is in NOT_WORKING state. "
127-
"Cable state: %s, component state: %s",
125+
"EV charger %s is in NOT_WORKING state. component states: %s",
128126
self._component_id,
129-
ev_data.cable_state,
130-
ev_data.component_state,
127+
ev_data.states,
131128
)
132129
return ComponentStatusEnum.NOT_WORKING
133130

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

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
from frequenz.channels import Receiver, Sender, select, selected_from
1111
from frequenz.channels.timer import SkipMissedAndDrift, Timer
1212
from frequenz.client.common.microgrid.components import ComponentId
13-
from frequenz.client.microgrid import ComponentStateCode
13+
from frequenz.client.microgrid.component import ComponentStateCode
1414
from typing_extensions import override
1515

1616
from ...._internal._asyncio import run_forever
@@ -84,11 +84,14 @@ def start(self) -> None:
8484

8585
def _is_working(self, pv_data: InverterData) -> bool:
8686
"""Return whether the given data indicates that the PV inverter is working."""
87-
return pv_data.component_state in (
88-
InverterComponentState.DISCHARGING,
89-
InverterComponentState.CHARGING,
90-
InverterComponentState.IDLE,
91-
InverterComponentState.STANDBY,
87+
return bool(
88+
{
89+
ComponentStateCode.DISCHARGING,
90+
ComponentStateCode.CHARGING,
91+
ComponentStateCode.READY,
92+
ComponentStateCode.STANDBY,
93+
}
94+
& pv_data.states
9295
)
9396

9497
def _is_stale(self, pv_data: InverterData) -> bool:
@@ -134,9 +137,9 @@ def _handle_pv_inverter_data(self, pv_data: InverterData) -> ComponentStatusEnum
134137

135138
if self._last_status == ComponentStatusEnum.WORKING:
136139
_logger.warning(
137-
"PV inverter %s is in NOT_WORKING state. Component state: %s",
140+
"PV inverter %s is in NOT_WORKING state. Component states: %s",
138141
self._component_id,
139-
pv_data.component_state,
142+
pv_data.states,
140143
)
141144
return ComponentStatusEnum.NOT_WORKING
142145

0 commit comments

Comments
 (0)