Skip to content
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
6 changes: 2 additions & 4 deletions RELEASE_NOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,15 @@

## Summary

<!-- Here goes a general summary of what this release is about -->
This release introduces the `v1alpha8` module to support a new API version.

## Upgrading

- The `typing-extensions` dependency minimum version was bumped to 4.6 to support Python 3.12.
- Changed the dependency reference for frequenz-api-common
- Renamed the old components module since it is replaced by electrical_components
- Updated tests to use the new electrical_components enums

## New Features

- Provide access to new API using new `v1alpha8` module.
<!-- Here goes the main new features and examples or instructions on how to use them -->

## Bug Fixes
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ classifiers = [
requires-python = ">= 3.11, < 4"
dependencies = [
"typing-extensions >= 4.6.0, < 5",
"frequenz-api-common @ git+https://github.com/frequenz-floss/frequenz-api-common.git@2e89add6a16d42b23612f0f791a499919f3738ed",
"frequenz-api-common >= 0.8.0, < 9",
]
dynamic = ["version"]

Expand Down
354 changes: 354 additions & 0 deletions src/frequenz/client/common/microgrid/components/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,354 @@
# License: MIT
# Copyright © 2022 Frequenz Energy-as-a-Service GmbH

"""Defines the components that can be used in a microgrid."""
from __future__ import annotations

from enum import Enum

# pylint: disable=no-name-in-module
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


class ComponentCategory(Enum):
"""Possible types of microgrid component."""

UNSPECIFIED = PBComponentCategory.COMPONENT_CATEGORY_UNSPECIFIED
"""An unknown component category.

Useful for error handling, and marking unknown components in
a list of components with otherwise known categories.
"""

GRID = PBComponentCategory.COMPONENT_CATEGORY_GRID
"""The point where the local microgrid is connected to the grid."""

METER = PBComponentCategory.COMPONENT_CATEGORY_METER
"""A meter, for measuring electrical metrics, e.g., current, voltage, etc."""

INVERTER = PBComponentCategory.COMPONENT_CATEGORY_INVERTER
"""An electricity generator, with batteries or solar energy."""

BATTERY = PBComponentCategory.COMPONENT_CATEGORY_BATTERY
"""A storage system for electrical energy, used by inverters."""

EV_CHARGER = PBComponentCategory.COMPONENT_CATEGORY_EV_CHARGER
"""A station for charging electrical vehicles."""

CHP = PBComponentCategory.COMPONENT_CATEGORY_CHP
"""A heat and power combustion plant (CHP stands for combined heat and power)."""

@classmethod
def from_proto(
cls, component_category: PBComponentCategory.ValueType
) -> ComponentCategory:
"""Convert a protobuf ComponentCategory message to ComponentCategory enum.

Args:
component_category: protobuf enum to convert

Returns:
Enum value corresponding to the protobuf message.
"""
if not any(t.value == component_category for t in ComponentCategory):
return ComponentCategory.UNSPECIFIED
return cls(component_category)

def to_proto(self) -> PBComponentCategory.ValueType:
"""Convert a ComponentCategory enum to protobuf ComponentCategory message.

Returns:
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
4 changes: 4 additions & 0 deletions src/frequenz/client/common/v1alpha8/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# License: MIT
# Copyright © 2025 Frequenz Energy-as-a-Service GmbH

"""Types introduced or modified in the v1alpha8 version of the common api."""
Loading
Loading