Skip to content

Commit

Permalink
Add missing state and error wrappers (#54)
Browse files Browse the repository at this point in the history
- **Remove some unnecessary pylint exceptions**
- **Add a missing `UNKNOWN` EV charger component state**
- **Return `UNKNOWN` instead of `UNSPECIFIED` for unknown states**
- **Wrap missing component errors**
- **Wrap missing component states**
- **Unify the style with the new wrappers**
- **Update release notes**
- **Prepare release notes for the v0.4.0 release**
  • Loading branch information
llucax authored May 31, 2024
2 parents 01a741e + 00f14e7 commit 10cd5c1
Show file tree
Hide file tree
Showing 6 changed files with 454 additions and 40 deletions.
16 changes: 15 additions & 1 deletion RELEASE_NOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

## Summary

<!-- Here goes a general summary of what this release is about -->
This release migrates to use `betterproto` and `grpclib` instead of `grpcio` and `protobuf` internally. It also stops *leaking* these internal libraries to downstream users. It should now be possible to use the client without having to use `grpclib` or `betterproto` directly.

## Upgrading

Expand All @@ -16,6 +16,8 @@

- The client now uses protobuf/grpc bindings generated [betterproto](https://github.com/danielgtaylor/python-betterproto) ([frequenz-microgrid-betterproto](https://github.com/frequenz-floss/frequenz-microgrid-betterproto-python)) instead of [grpcio](https://pypi.org/project/grpcio/) ([frequenz-api-microgrid](https://github.com/frequenz-floss/frequenz-api-microgrid)). If you were using the bindings directly, you might need to do some minor adjustments to your code.

- If an unknown EV charger component state is received, it will now be set to `EVChargerComponentState.UNKNOWN` instead of `EVChargerComponentState.UNSPECIFIED`.

## New Features

- The client now raises more specific exceptions based on the gRPC status code, so you can more easily handle different types of errors.
Expand All @@ -39,6 +41,18 @@
...
```

- We now expose component errors as part of the streamed component data:

* `BatteryData.errors`
* `InverterData.errors`

- We now expose component states as part of the streamed component data:

* `BatteryData.component_state` and `BatteryData.relay_state`
* `InverterData.component_state`

- Added the missing `EVChargerComponentState.UNKNOWN` state.

## Bug Fixes

- Fix a leakage of `GrpcStreamBroadcaster` instances.
Expand Down
23 changes: 22 additions & 1 deletion src/frequenz/client/microgrid/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,20 @@
InverterData,
MeterData,
)
from ._component_states import EVChargerCableState, EVChargerComponentState
from ._component_error import (
BatteryError,
BatteryErrorCode,
ErrorLevel,
InverterError,
InverterErrorCode,
)
from ._component_states import (
BatteryComponentState,
BatteryRelayState,
EVChargerCableState,
EVChargerComponentState,
InverterComponentState,
)
from ._connection import Connection
from ._exception import (
ClientError,
Expand All @@ -52,7 +65,11 @@

__all__ = [
"ApiClient",
"BatteryComponentState",
"BatteryData",
"BatteryError",
"BatteryErrorCode",
"BatteryRelayState",
"ClientError",
"Component",
"ComponentCategory",
Expand All @@ -67,12 +84,16 @@
"EVChargerData",
"EntityAlreadyExists",
"EntityNotFound",
"ErrorLevel",
"Fuse",
"GridMetadata",
"GrpcError",
"InternalError",
"InvalidArgument",
"InverterComponentState",
"InverterData",
"InverterError",
"InverterErrorCode",
"InverterType",
"Location",
"Metadata",
Expand Down
38 changes: 22 additions & 16 deletions src/frequenz/client/microgrid/_component_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,15 @@
from typing import Self

from frequenz.microgrid.betterproto.frequenz.api import microgrid
from frequenz.microgrid.betterproto.frequenz.api.microgrid import battery, inverter

from ._component_states import EVChargerCableState, EVChargerComponentState
from ._component_error import BatteryError, InverterError
from ._component_states import (
BatteryComponentState,
BatteryRelayState,
EVChargerCableState,
EVChargerComponentState,
InverterComponentState,
)


@dataclass(frozen=True)
Expand Down Expand Up @@ -173,7 +179,6 @@ class BatteryData(ComponentData): # pylint: disable=too-many-instance-attribute
capacity: float
"""The capacity of the battery in Wh (Watt-hour)."""

# pylint: disable=line-too-long
power_inclusion_lower_bound: float
"""Lower inclusion bound for battery power in watts.
Expand Down Expand Up @@ -217,18 +222,17 @@ class BatteryData(ComponentData): # pylint: disable=too-many-instance-attribute
[`frequenz.api.common.metrics_pb2.Metric.system_exclusion_bounds`][] for more
details.
"""
# pylint: enable=line-too-long

temperature: float
"""The (average) temperature reported by the battery, in Celsius (°C)."""

_relay_state: battery.RelayState
relay_state: BatteryRelayState
"""State of the battery relay."""

_component_state: battery.ComponentState
component_state: BatteryComponentState
"""State of the battery."""

_errors: list[battery.Error]
errors: list[BatteryError]
"""List of errors in protobuf struct."""

@classmethod
Expand All @@ -254,9 +258,11 @@ def from_proto(cls, raw: microgrid.ComponentData) -> Self:
power_inclusion_upper_bound=raw_power.system_inclusion_bounds.upper,
power_exclusion_upper_bound=raw_power.system_exclusion_bounds.upper,
temperature=raw.battery.data.temperature.avg,
_relay_state=raw.battery.state.relay_state,
_component_state=raw.battery.state.component_state,
_errors=list(raw.battery.errors),
relay_state=BatteryRelayState.from_pb(raw.battery.state.relay_state),
component_state=BatteryComponentState.from_pb(
raw.battery.state.component_state
),
errors=[BatteryError.from_pb(e) for e in raw.battery.errors],
)
battery_data._set_raw(raw=raw)
return battery_data
Expand Down Expand Up @@ -314,7 +320,6 @@ class InverterData(ComponentData): # pylint: disable=too-many-instance-attribut
phase/line 1, 2 and 3 respectively.
"""

# pylint: disable=line-too-long
active_power_inclusion_lower_bound: float
"""Lower inclusion bound for inverter power in watts.
Expand Down Expand Up @@ -358,15 +363,14 @@ class InverterData(ComponentData): # pylint: disable=too-many-instance-attribut
[`frequenz.api.common.metrics_pb2.Metric.system_exclusion_bounds`][] for more
details.
"""
# pylint: enable=line-too-long

frequency: float
"""AC frequency, in Hertz (Hz)."""

_component_state: inverter.ComponentState
component_state: InverterComponentState
"""State of the inverter."""

_errors: list[inverter.Error]
errors: list[InverterError]
"""List of errors from the component."""

@classmethod
Expand Down Expand Up @@ -410,8 +414,10 @@ def from_proto(cls, raw: microgrid.ComponentData) -> Self:
active_power_inclusion_upper_bound=raw_power.system_inclusion_bounds.upper,
active_power_exclusion_upper_bound=raw_power.system_exclusion_bounds.upper,
frequency=raw.inverter.data.ac.frequency.value,
_component_state=raw.inverter.state.component_state,
_errors=list(raw.inverter.errors),
component_state=InverterComponentState.from_pb(
raw.inverter.state.component_state
),
errors=[InverterError.from_pb(e) for e in raw.inverter.errors],
)

inverter_data._set_raw(raw=raw)
Expand Down
Loading

0 comments on commit 10cd5c1

Please sign in to comment.