From eb8f412101c7a049f8121407fdfc0db011e5142f Mon Sep 17 00:00:00 2001 From: cyiallou - Costas <42914163+cyiallou@users.noreply.github.com> Date: Thu, 14 Nov 2024 13:10:59 +0100 Subject: [PATCH 1/2] Add component state codes Signed-off-by: cyiallou - Costas <42914163+cyiallou@users.noreply.github.com> --- RELEASE_NOTES.md | 3 +- .../common/microgrid/components/__init__.py | 107 ++++++++++++++++++ tests/test_client_common.py | 11 +- 3 files changed, 119 insertions(+), 2 deletions(-) diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index be9a5da..8fe0b0d 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -10,7 +10,8 @@ Update of the Pagination `Params` data class. ## New Features -* Additional information for energy metric +* Additional information for energy metric. +* Add component state codes. ## Bug Fixes diff --git a/src/frequenz/client/common/microgrid/components/__init__.py b/src/frequenz/client/common/microgrid/components/__init__.py index 0008301..d61c939 100644 --- a/src/frequenz/client/common/microgrid/components/__init__.py +++ b/src/frequenz/client/common/microgrid/components/__init__.py @@ -10,6 +10,9 @@ from frequenz.api.common.v1.microgrid.components.components_pb2 import ( ComponentCategory as PBComponentCategory, ) +from frequenz.api.common.v1.microgrid.components.components_pb2 import ( + ComponentStateCode as PBComponentStateCode, +) # pylint: enable=no-name-in-module @@ -65,3 +68,107 @@ def to_proto(self) -> PBComponentCategory.ValueType: Enum value corresponding to the protobuf message. """ return self.value + + +class ComponentStateCode(Enum): + """All possible states of a microgrid component.""" + + UNSPECIFIED = PBComponentStateCode.COMPONENT_STATE_CODE_UNSPECIFIED + """Default value when the component state is not explicitly set.""" + + UNKNOWN = PBComponentStateCode.COMPONENT_STATE_CODE_UNKNOWN + """State when the component is in an unknown or undefined condition. + + This is used when the sender is unable to classify the component into any + other state. + """ + SWITCHING_OFF = PBComponentStateCode.COMPONENT_STATE_CODE_SWITCHING_OFF + """State when the component is in the process of switching off.""" + + OFF = PBComponentStateCode.COMPONENT_STATE_CODE_OFF + """State when the component has successfully switched off.""" + + SWITCHING_ON = PBComponentStateCode.COMPONENT_STATE_CODE_SWITCHING_ON + """State when the component is in the process of switching on from an off state.""" + + STANDBY = PBComponentStateCode.COMPONENT_STATE_CODE_STANDBY + """State when the component is in standby mode, and not immediately ready for operation.""" + + READY = PBComponentStateCode.COMPONENT_STATE_CODE_READY + """State when the component is fully operational and ready for use.""" + + CHARGING = PBComponentStateCode.COMPONENT_STATE_CODE_CHARGING + """State when the component is actively consuming energy.""" + + DISCHARGING = PBComponentStateCode.COMPONENT_STATE_CODE_DISCHARGING + """State when the component is actively producing or releasing energy.""" + + ERROR = PBComponentStateCode.COMPONENT_STATE_CODE_ERROR + """State when the component is in an error state and may need attention.""" + + EV_CHARGING_CABLE_UNPLUGGED = ( + PBComponentStateCode.COMPONENT_STATE_CODE_EV_CHARGING_CABLE_UNPLUGGED + ) + """The Electric Vehicle (EV) charging cable is unplugged from the charging station.""" + + EV_CHARGING_CABLE_PLUGGED_AT_STATION = ( + PBComponentStateCode.COMPONENT_STATE_CODE_EV_CHARGING_CABLE_PLUGGED_AT_STATION + ) + """The EV charging cable is plugged into the charging station.""" + + EV_CHARGING_CABLE_PLUGGED_AT_EV = ( + PBComponentStateCode.COMPONENT_STATE_CODE_EV_CHARGING_CABLE_PLUGGED_AT_EV + ) + """The EV charging cable is plugged into the vehicle.""" + + EV_CHARGING_CABLE_LOCKED_AT_STATION = ( + PBComponentStateCode.COMPONENT_STATE_CODE_EV_CHARGING_CABLE_LOCKED_AT_STATION + ) + """The EV charging cable is locked at the charging station end, indicating + readiness for charging.""" + + EV_CHARGING_CABLE_LOCKED_AT_EV = ( + PBComponentStateCode.COMPONENT_STATE_CODE_EV_CHARGING_CABLE_LOCKED_AT_EV + ) + """The EV charging cable is locked at the vehicle end, indicating that charging is active.""" + + RELAY_OPEN = PBComponentStateCode.COMPONENT_STATE_CODE_RELAY_OPEN + """The relay is in an open state, meaning no current can flow through.""" + + RELAY_CLOSED = PBComponentStateCode.COMPONENT_STATE_CODE_RELAY_CLOSED + """The relay is in a closed state, allowing current to flow.""" + + PRECHARGER_OPEN = PBComponentStateCode.COMPONENT_STATE_CODE_PRECHARGER_OPEN + """The precharger circuit is open, meaning it's not currently active.""" + + PRECHARGER_PRECHARGING = ( + PBComponentStateCode.COMPONENT_STATE_CODE_PRECHARGER_PRECHARGING + ) + """The precharger is in a precharging state, preparing the main circuit for activation.""" + + PRECHARGER_CLOSED = PBComponentStateCode.COMPONENT_STATE_CODE_PRECHARGER_CLOSED + """The precharger circuit is closed, allowing full current to flow to the main circuit.""" + + @classmethod + def from_proto( + cls, component_state: PBComponentStateCode.ValueType + ) -> ComponentStateCode: + """Convert a protobuf ComponentStateCode message to ComponentStateCode enum. + + Args: + component_state: protobuf enum to convert + + Returns: + Enum value corresponding to the protobuf message. + """ + if not any(c.value == component_state for c in ComponentStateCode): + return ComponentStateCode.UNSPECIFIED + return cls(component_state) + + def to_proto(self) -> PBComponentStateCode.ValueType: + """Convert a ComponentStateCode enum to protobuf ComponentStateCode message. + + Returns: + Enum value corresponding to the protobuf message. + """ + return self.value diff --git a/tests/test_client_common.py b/tests/test_client_common.py index c6ae539..f1d39cb 100644 --- a/tests/test_client_common.py +++ b/tests/test_client_common.py @@ -3,10 +3,19 @@ """Tests for the frequenz.client.common package.""" -from frequenz.client.common.microgrid.components import ComponentCategory +from frequenz.client.common.microgrid.components import ( + ComponentCategory, + ComponentStateCode, +) def test_components() -> None: """Test the components.""" for category in ComponentCategory: assert ComponentCategory.from_proto(category.to_proto()) == category + + +def test_component_state_code() -> None: + """Test the component state code.""" + for state_code in ComponentStateCode: + assert ComponentStateCode.from_proto(state_code.to_proto()) == state_code From dbc6d5113722ce34d08bc2811c9a5b13b128a5f3 Mon Sep 17 00:00:00 2001 From: cyiallou - Costas <42914163+cyiallou@users.noreply.github.com> Date: Thu, 14 Nov 2024 13:11:59 +0100 Subject: [PATCH 2/2] Add component error codes Signed-off-by: cyiallou - Costas <42914163+cyiallou@users.noreply.github.com> --- RELEASE_NOTES.md | 1 + .../common/microgrid/components/__init__.py | 180 ++++++++++++++++++ tests/test_client_common.py | 7 + 3 files changed, 188 insertions(+) diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 8fe0b0d..db812d7 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -12,6 +12,7 @@ Update of the Pagination `Params` data class. * Additional information for energy metric. * Add component state codes. +* Add component error codes. ## Bug Fixes diff --git a/src/frequenz/client/common/microgrid/components/__init__.py b/src/frequenz/client/common/microgrid/components/__init__.py index d61c939..013c26a 100644 --- a/src/frequenz/client/common/microgrid/components/__init__.py +++ b/src/frequenz/client/common/microgrid/components/__init__.py @@ -10,6 +10,9 @@ from frequenz.api.common.v1.microgrid.components.components_pb2 import ( ComponentCategory as PBComponentCategory, ) +from frequenz.api.common.v1.microgrid.components.components_pb2 import ( + ComponentErrorCode as PBComponentErrorCode, +) from frequenz.api.common.v1.microgrid.components.components_pb2 import ( ComponentStateCode as PBComponentStateCode, ) @@ -172,3 +175,180 @@ def to_proto(self) -> PBComponentStateCode.ValueType: Enum value corresponding to the protobuf message. """ return self.value + + +class ComponentErrorCode(Enum): + """All possible errors that can occur across all microgrid component categories.""" + + UNSPECIFIED = PBComponentErrorCode.COMPONENT_ERROR_CODE_UNSPECIFIED + """Default value. No specific error is specified.""" + + UNKNOWN = PBComponentErrorCode.COMPONENT_ERROR_CODE_UNKNOWN + """The component is reporting an unknown or an undefined error, and the sender + cannot parse the component error to any of the variants below.""" + + SWITCH_ON_FAULT = PBComponentErrorCode.COMPONENT_ERROR_CODE_SWITCH_ON_FAULT + """Error indicating that the component could not be switched on.""" + + UNDERVOLTAGE = PBComponentErrorCode.COMPONENT_ERROR_CODE_UNDERVOLTAGE + """Error indicating that the component is operating under the minimum rated + voltage.""" + + OVERVOLTAGE = PBComponentErrorCode.COMPONENT_ERROR_CODE_OVERVOLTAGE + """Error indicating that the component is operating over the maximum rated + voltage.""" + + OVERCURRENT = PBComponentErrorCode.COMPONENT_ERROR_CODE_OVERCURRENT + """Error indicating that the component is drawing more current than the + maximum rated value.""" + + OVERCURRENT_CHARGING = ( + PBComponentErrorCode.COMPONENT_ERROR_CODE_OVERCURRENT_CHARGING + ) + """Error indicating that the component's consumption current is over the + maximum rated value during charging.""" + + OVERCURRENT_DISCHARGING = ( + PBComponentErrorCode.COMPONENT_ERROR_CODE_OVERCURRENT_DISCHARGING + ) + """Error indicating that the component's production current is over the + maximum rated value during discharging.""" + + OVERTEMPERATURE = PBComponentErrorCode.COMPONENT_ERROR_CODE_OVERTEMPERATURE + """Error indicating that the component is operating over the maximum rated + temperature.""" + + UNDERTEMPERATURE = PBComponentErrorCode.COMPONENT_ERROR_CODE_UNDERTEMPERATURE + """Error indicating that the component is operating under the minimum rated + temperature.""" + + HIGH_HUMIDITY = PBComponentErrorCode.COMPONENT_ERROR_CODE_HIGH_HUMIDITY + """Error indicating that the component is exposed to high humidity levels over + the maximum rated value.""" + + FUSE_ERROR = PBComponentErrorCode.COMPONENT_ERROR_CODE_FUSE_ERROR + """Error indicating that the component's fuse has blown.""" + + PRECHARGE_ERROR = PBComponentErrorCode.COMPONENT_ERROR_CODE_PRECHARGE_ERROR + """Error indicating that the component's precharge unit has failed.""" + + PLAUSIBILITY_ERROR = PBComponentErrorCode.COMPONENT_ERROR_CODE_PLAUSIBILITY_ERROR + """Error indicating plausibility issues within the system involving this + component.""" + + UNDERVOLTAGE_SHUTDOWN = ( + PBComponentErrorCode.COMPONENT_ERROR_CODE_UNDERVOLTAGE_SHUTDOWN + ) + """Error indicating system shutdown due to undervoltage involving this + component.""" + + EV_UNEXPECTED_PILOT_FAILURE = ( + PBComponentErrorCode.COMPONENT_ERROR_CODE_EV_UNEXPECTED_PILOT_FAILURE + ) + """Error indicating unexpected pilot failure in an electric vehicle (EV) + component.""" + + FAULT_CURRENT = PBComponentErrorCode.COMPONENT_ERROR_CODE_FAULT_CURRENT + """Error indicating fault current detected in the component.""" + + SHORT_CIRCUIT = PBComponentErrorCode.COMPONENT_ERROR_CODE_SHORT_CIRCUIT + """Error indicating a short circuit detected in the component.""" + + CONFIG_ERROR = PBComponentErrorCode.COMPONENT_ERROR_CODE_CONFIG_ERROR + """Error indicating a configuration error related to the component.""" + + ILLEGAL_COMPONENT_STATE_CODE_REQUESTED = ( + PBComponentErrorCode.COMPONENT_ERROR_CODE_ILLEGAL_COMPONENT_STATE_CODE_REQUESTED + ) + """Error indicating an illegal state requested for the component.""" + + HARDWARE_INACCESSIBLE = ( + PBComponentErrorCode.COMPONENT_ERROR_CODE_HARDWARE_INACCESSIBLE + ) + """Error indicating that the hardware of the component is inaccessible.""" + + INTERNAL = PBComponentErrorCode.COMPONENT_ERROR_CODE_INTERNAL + """Error indicating an internal error within the component.""" + + UNAUTHORIZED = PBComponentErrorCode.COMPONENT_ERROR_CODE_UNAUTHORIZED + """Error indicating that the component is unauthorized to perform the + last requested action.""" + + EV_CHARGING_CABLE_UNPLUGGED_FROM_STATION = ( + PBComponentErrorCode.COMPONENT_ERROR_CODE_EV_CHARGING_CABLE_UNPLUGGED_FROM_STATION + ) + """Error indicating electric vehicle (EV) cable was abruptly unplugged from + the charging station.""" + + EV_CHARGING_CABLE_UNPLUGGED_FROM_EV = ( + PBComponentErrorCode.COMPONENT_ERROR_CODE_EV_CHARGING_CABLE_UNPLUGGED_FROM_EV + ) + """Error indicating electric vehicle (EV) cable was abruptly unplugged from + the vehicle.""" + + EV_CHARGING_CABLE_LOCK_FAILED = ( + PBComponentErrorCode.COMPONENT_ERROR_CODE_EV_CHARGING_CABLE_LOCK_FAILED + ) + """Error indicating electric vehicle (EV) cable lock failure.""" + + EV_CHARGING_CABLE_INVALID = ( + PBComponentErrorCode.COMPONENT_ERROR_CODE_EV_CHARGING_CABLE_INVALID + ) + """Error indicating an invalid electric vehicle (EV) cable.""" + + EV_CONSUMER_INCOMPATIBLE = ( + PBComponentErrorCode.COMPONENT_ERROR_CODE_EV_CONSUMER_INCOMPATIBLE + ) + """Error indicating an incompatible electric vehicle (EV) plug.""" + + BATTERY_IMBALANCE = PBComponentErrorCode.COMPONENT_ERROR_CODE_BATTERY_IMBALANCE + """Error indicating a battery system imbalance.""" + + BATTERY_LOW_SOH = PBComponentErrorCode.COMPONENT_ERROR_CODE_BATTERY_LOW_SOH + """Error indicating a low state of health (SOH) detected in the battery.""" + + BATTERY_BLOCK_ERROR = PBComponentErrorCode.COMPONENT_ERROR_CODE_BATTERY_BLOCK_ERROR + """Error indicating a battery block error.""" + + BATTERY_CONTROLLER_ERROR = ( + PBComponentErrorCode.COMPONENT_ERROR_CODE_BATTERY_CONTROLLER_ERROR + ) + """Error indicating a battery controller error.""" + + BATTERY_RELAY_ERROR = PBComponentErrorCode.COMPONENT_ERROR_CODE_BATTERY_RELAY_ERROR + """Error indicating a battery relay error.""" + + BATTERY_CALIBRATION_NEEDED = ( + PBComponentErrorCode.COMPONENT_ERROR_CODE_BATTERY_CALIBRATION_NEEDED + ) + """Error indicating that battery calibration is needed.""" + + RELAY_CYCLE_LIMIT_REACHED = ( + PBComponentErrorCode.COMPONENT_ERROR_CODE_RELAY_CYCLE_LIMIT_REACHED + ) + """Error indicating that the relays have been cycled for the maximum number of + times.""" + + @classmethod + def from_proto( + cls, component_error_code: PBComponentErrorCode.ValueType + ) -> ComponentErrorCode: + """Convert a protobuf ComponentErrorCode message to ComponentErrorCode enum. + + Args: + component_error_code: protobuf enum to convert + + Returns: + Enum value corresponding to the protobuf message. + """ + if not any(c.value == component_error_code for c in ComponentErrorCode): + return ComponentErrorCode.UNSPECIFIED + return cls(component_error_code) + + def to_proto(self) -> PBComponentErrorCode.ValueType: + """Convert a ComponentErrorCode enum to protobuf ComponentErrorCode message. + + Returns: + Enum value corresponding to the protobuf message. + """ + return self.value diff --git a/tests/test_client_common.py b/tests/test_client_common.py index f1d39cb..e9d865d 100644 --- a/tests/test_client_common.py +++ b/tests/test_client_common.py @@ -5,6 +5,7 @@ from frequenz.client.common.microgrid.components import ( ComponentCategory, + ComponentErrorCode, ComponentStateCode, ) @@ -19,3 +20,9 @@ def test_component_state_code() -> None: """Test the component state code.""" for state_code in ComponentStateCode: assert ComponentStateCode.from_proto(state_code.to_proto()) == state_code + + +def test_component_error_code() -> None: + """Test the component error code.""" + for error_code in ComponentErrorCode: + assert ComponentErrorCode.from_proto(error_code.to_proto()) == error_code