Skip to content

Commit 985ad34

Browse files
authored
Prepare for the v0.6.0 release (#101)
This PR prepare the release notes for the release and also merges v0.5.2 to bring in the new `set_power_reactive()` method.
2 parents a8124b2 + 16321ac commit 985ad34

File tree

3 files changed

+72
-8
lines changed

3 files changed

+72
-8
lines changed

RELEASE_NOTES.md

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,5 @@
11
# Frequenz Microgrid API Client Release Notes
22

3-
## Summary
4-
5-
<!-- Here goes a general summary of what this release is about -->
6-
73
## Upgrading
84

95
- `ApiClient`:
@@ -18,7 +14,4 @@
1814
## New Features
1915

2016
- The client now inherits from `frequenz.client.base.BaseApiClient`, so it provides a few new features, like `disconnect()`ing or using it as a context manager. Please refer to the [`BaseApiClient` documentation](https://frequenz-floss.github.io/frequenz-client-base-python/latest/reference/frequenz/client/base/client/#frequenz.client.base.client.BaseApiClient) for more information on these features.
21-
22-
## Bug Fixes
23-
24-
<!-- Here goes notable bug fixes that are worth a special mention or explanation -->
17+
- The client now supports setting reactive power for components through the new `set_reactive_power` method.

src/frequenz/client/microgrid/_client.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -432,6 +432,34 @@ async def set_power( # noqa: DOC502 (raises ApiClientError indirectly)
432432
method_name="SetPowerActive",
433433
)
434434

435+
async def set_reactive_power( # noqa: DOC502 (raises ApiClientError indirectly)
436+
self, component_id: int, reactive_power_var: float
437+
) -> None:
438+
"""Send request to the Microgrid to set reactive power for component.
439+
440+
Negative values are for inductive (lagging) power , and positive values are for
441+
capacitive (leading) power.
442+
443+
Args:
444+
component_id: id of the component to set power.
445+
reactive_power_var: reactive power to set for the component.
446+
447+
Raises:
448+
ApiClientError: If the are any errors communicating with the Microgrid API,
449+
most likely a subclass of
450+
[GrpcError][frequenz.client.microgrid.GrpcError].
451+
"""
452+
await client.call_stub_method(
453+
self,
454+
lambda: self.stub.SetPowerReactive(
455+
microgrid_pb2.SetPowerReactiveParam(
456+
component_id=component_id, power=reactive_power_var
457+
),
458+
timeout=int(DEFAULT_GRPC_CALL_TIMEOUT),
459+
),
460+
method_name="SetPowerReactive",
461+
)
462+
435463
async def set_bounds( # noqa: DOC503 (raises ApiClientError indirectly)
436464
self,
437465
component_id: int,

tests/test_client.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ def __init__(self, *, retry_strategy: retry.Strategy | None = None) -> None:
4242
mock_stub.ListComponents = mock.AsyncMock("ListComponents")
4343
mock_stub.ListConnections = mock.AsyncMock("ListConnections")
4444
mock_stub.SetPowerActive = mock.AsyncMock("SetPowerActive")
45+
mock_stub.SetPowerReactive = mock.AsyncMock("SetPowerReactive")
4546
mock_stub.AddInclusionBounds = mock.AsyncMock("AddInclusionBounds")
4647
mock_stub.StreamComponentData = mock.Mock("StreamComponentData")
4748
super().__init__("grpc://mock_host:1234", retry_strategy=retry_strategy)
@@ -607,6 +608,48 @@ async def test_set_power_grpc_error() -> None:
607608
await client.set_power(component_id=83, power_w=100.0)
608609

609610

611+
@pytest.mark.parametrize(
612+
"reactive_power_var",
613+
[0, 0.0, 12, -75, 0.1, -0.0001, 134.0],
614+
)
615+
async def test_set_reactive_power_ok(
616+
reactive_power_var: float, meter83: microgrid_pb2.Component
617+
) -> None:
618+
"""Test if charge is able to charge component."""
619+
client = _TestClient()
620+
client.mock_stub.ListComponents.return_value = microgrid_pb2.ComponentList(
621+
components=[meter83]
622+
)
623+
624+
await client.set_reactive_power(
625+
component_id=83, reactive_power_var=reactive_power_var
626+
)
627+
client.mock_stub.SetPowerReactive.assert_called_once()
628+
call_args = client.mock_stub.SetPowerReactive.call_args[0]
629+
assert call_args[0] == microgrid_pb2.SetPowerReactiveParam(
630+
component_id=83, power=reactive_power_var
631+
)
632+
633+
634+
async def test_set_reactive_power_grpc_error() -> None:
635+
"""Test set_power() raises ApiClientError when the gRPC call fails."""
636+
client = _TestClient()
637+
client.mock_stub.SetPowerReactive.side_effect = grpc.aio.AioRpcError(
638+
mock.MagicMock(name="mock_status"),
639+
mock.MagicMock(name="mock_initial_metadata"),
640+
mock.MagicMock(name="mock_trailing_metadata"),
641+
"fake grpc details",
642+
"fake grpc debug_error_string",
643+
)
644+
with pytest.raises(
645+
ApiClientError,
646+
match=r"Failed calling 'SetPowerReactive' on 'grpc://mock_host:1234': .* "
647+
r"<status=<MagicMock name='mock_status\.name' id='.*'>>: fake grpc details "
648+
r"\(fake grpc debug_error_string\)",
649+
):
650+
await client.set_reactive_power(component_id=83, reactive_power_var=100.0)
651+
652+
610653
@pytest.mark.parametrize(
611654
"bounds",
612655
[

0 commit comments

Comments
 (0)