Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add component states and error codes #44

Merged
merged 2 commits into from
Nov 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion RELEASE_NOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ Update of the Pagination `Params` data class.

## New Features

* Additional information for energy metric
* Additional information for energy metric.
* Add component state codes.
* Add component error codes.

## Bug Fixes

Expand Down
287 changes: 287 additions & 0 deletions src/frequenz/client/common/microgrid/components/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@
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,
)

# pylint: enable=no-name-in-module

Expand Down Expand Up @@ -65,3 +71,284 @@ 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


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
18 changes: 17 additions & 1 deletion tests/test_client_common.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,26 @@

"""Tests for the frequenz.client.common package."""

from frequenz.client.common.microgrid.components import ComponentCategory
from frequenz.client.common.microgrid.components import (
ComponentCategory,
ComponentErrorCode,
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


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
Loading