Skip to content

Commit a8f30de

Browse files
authored
Upgrade to microgrid client v0.4.0 (#955)
- **Bump frequenz-client-microgrid to v0.4.0** - **Use `GrpcError` instead of `grpc.aio.AioRpcError`** - **Avoid repetition on error handling** - **Use a server URL to connect to the microgrid API** - **Use new microgrid API wrapped types** - **Stop using the `mock_api` for testing** - **Remove the, now unused, `mock_api` and its tests** - **Silence `hpack` debug logging** - **Fix mock return value** - **Avoid disabling some pylint checks when unnecessary** - **Remove unsed protobuf and grpcio dependencies**
2 parents d5d74a3 + 3bafab6 commit a8f30de

34 files changed

+545
-1021
lines changed

RELEASE_NOTES.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,21 @@
66

77
## Upgrading
88

9+
- The `frequenz-client-microgrid` dependency was bumped to v0.4.0. If you are using the client directly in your code, you will need to upgrade too.
10+
911
- Calls to `microgrid.*_pool` methods now always need to specified a priority value, corresponding to the requirements/priority of the actor making the call.
1012

1113
- The `microgrid.*_pool` methods would only accept keyword arguments from now on.
1214

15+
- The `microgrid.initialize()` method now takes a `server_url` instead of a `host` and `port`.
16+
17+
The following format is expected: `grpc://hostname{:port}{?ssl=ssl}`, where the port should be an int between `0` and `65535` (defaulting to `9090`) and `ssl` should be a boolean (defaulting to `false`). For example: `grpc://localhost` or `grpc://localhost:1090?ssl=true`.
18+
19+
The default was also removed, so you always need to specify the server URL.
20+
21+
This applies to the `ConnectionManager` as well, which also now doesn't expose the `host` and `port` attributes, only the `server_url`. If you need to extract the host or port from the `server_url`, you can use the standard Python `urllib.parse.urlparse()` function.
22+
23+
1324
## New Features
1425

1526
- Calls to `microgrid.*_pool` methods now accept an optional `in_shifting_group` parameter. Power requests sent to `*_pool` instances that have the `in_shifting_group` flag set, will get resolved separately, and their target power will be added to the target power calculated from regular actors, if any, which would, in effect, shift the zero for the regular actors by the target power from the shifting group.

benchmarks/power_distribution/power_distributor.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -137,10 +137,9 @@ async def run_test( # pylint: disable=too-many-locals
137137

138138
async def run() -> None:
139139
"""Create microgrid api and run tests."""
140-
# pylint: disable=protected-access
141-
142140
await microgrid.initialize(
143-
HOST, PORT, ResamplerConfig(resampling_period=timedelta(seconds=1.0))
141+
"grpc://microgrid.sandbox.api.frequenz.io:62060",
142+
ResamplerConfig(resampling_period=timedelta(seconds=1.0)),
144143
)
145144

146145
all_batteries: set[Component] = connection_manager.get().component_graph.components(

benchmarks/timeseries/benchmark_datasourcing.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,12 +49,12 @@ def enable_mock_client(client: MockMicrogridClient) -> None:
4949
Args:
5050
client: the mock microgrid client to enable.
5151
"""
52-
# pylint: disable=protected-access
53-
microgrid.connection_manager._CONNECTION_MANAGER = client.mock_microgrid
52+
microgrid.connection_manager._CONNECTION_MANAGER = ( # pylint: disable=protected-access
53+
client.mock_microgrid
54+
)
5455

5556

56-
# pylint: disable=too-many-locals
57-
async def benchmark_data_sourcing(
57+
async def benchmark_data_sourcing( # pylint: disable=too-many-locals
5858
num_ev_chargers: int, num_msgs_per_battery: int
5959
) -> None:
6060
"""Benchmark the data sourcing actor.

docs/tutorials/getting_started.md

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -44,13 +44,11 @@ microgrid.
4444
```python
4545
async def run() -> None:
4646
# This points to the default Frequenz microgrid sandbox
47-
microgrid_host = "microgrid.sandbox.api.frequenz.io"
48-
microgrid_port = 62060
47+
server_url = "grpc://microgrid.sandbox.api.frequenz.io:62060",
4948

5049
# Initialize the microgrid
5150
await microgrid.initialize(
52-
microgrid_host,
53-
microgrid_port,
51+
server_url,
5452
ResamplerConfig(resampling_period=timedelta(seconds=1)),
5553
)
5654

@@ -106,13 +104,11 @@ from frequenz.sdk.actor import ResamplerConfig
106104

107105
async def run() -> None:
108106
# This points to the default Frequenz microgrid sandbox
109-
microgrid_host = "microgrid.sandbox.api.frequenz.io"
110-
microgrid_port = 62060
107+
server_url = "grpc://microgrid.sandbox.api.frequenz.io:62060",
111108

112109
# Initialize the microgrid
113110
await microgrid.initialize(
114-
microgrid_host,
115-
microgrid_port,
111+
server_url,
116112
ResamplerConfig(resampling_period=timedelta(seconds=1)),
117113
)
118114

examples/battery_pool.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,11 @@ async def main() -> None:
2222
logging.basicConfig(
2323
level=logging.DEBUG, format="%(asctime)s %(name)s %(levelname)s:%(message)s"
2424
)
25+
# Reduce undesired noise from hpack
26+
logging.getLogger("hpack.hpack").setLevel(logging.INFO)
27+
2528
await microgrid.initialize(
26-
host=HOST,
27-
port=PORT,
29+
"grpc://microgrid.sandbox.api.frequenz.io:62060",
2830
resampler_config=ResamplerConfig(resampling_period=timedelta(seconds=1.0)),
2931
)
3032

mkdocs.yml

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -114,15 +114,11 @@ plugins:
114114
import:
115115
# See https://mkdocstrings.github.io/python/usage/#import for details
116116
- https://docs.python.org/3/objects.inv
117-
- https://frequenz-floss.github.io/frequenz-api-common/v0.3/objects.inv
118117
- https://frequenz-floss.github.io/frequenz-channels-python/v0.16/objects.inv
119-
- https://frequenz-floss.github.io/frequenz-api-microgrid/v0.15/objects.inv
120-
- https://grpc.github.io/grpc/python/objects.inv
118+
- https://frequenz-floss.github.io/frequenz-client-microgrid-python/v0.4/objects.inv
121119
- https://networkx.org/documentation/stable/objects.inv
122120
- https://numpy.org/doc/stable/objects.inv
123-
- https://protobuf.readthedocs.io/en/latest/objects.inv
124121
- https://typing-extensions.readthedocs.io/en/stable/objects.inv
125-
- https://watchfiles.helpmanual.io/objects.inv
126122
# Note this plugin must be loaded after mkdocstrings to be able to use macros
127123
# inside docstrings. See the comment in `docs/_scripts/macros.py` for more
128124
# details

pyproject.toml

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -26,23 +26,15 @@ classifiers = [
2626
]
2727
requires-python = ">= 3.11, < 4"
2828
dependencies = [
29-
"frequenz-api-microgrid >= 0.15.3, < 0.16.0",
3029
# Make sure to update the mkdocs.yml file when
3130
# changing the version
3231
# (plugins.mkdocstrings.handlers.python.import)
32+
"frequenz-client-microgrid >= 0.4.0, < 0.5.0",
3333
"frequenz-channels >= 1.0.0-rc1, < 2.0.0",
34-
"frequenz-client-microgrid >= 0.3.0, < 0.4.0",
35-
"google-api-python-client >= 2.71, < 3",
36-
"grpcio >= 1.60.1, < 2",
37-
"grpcio-tools >= 1.60.1, < 2",
3834
"networkx >= 2.8, < 4",
3935
"numpy >= 1.26.4, < 2",
40-
"protobuf >= 4.21.6, < 6",
4136
"pydantic >= 2.3, < 3",
42-
"timezonefinder >= 6.2.0, < 7",
43-
"tqdm >= 4.38.0, < 5",
4437
"typing_extensions >= 4.6.1, < 5",
45-
"watchfiles >= 0.15.0",
4638
]
4739
dynamic = ["version"]
4840

@@ -73,7 +65,6 @@ dev-mkdocs = [
7365
]
7466
dev-mypy = [
7567
"mypy == 1.10.0",
76-
"grpc-stubs == 1.24.12", # This dependency introduces breaking changes in patch releases
7768
"types-Markdown == 3.6.0.20240316",
7869
"types-protobuf == 5.26.0.20240422",
7970
"types-setuptools == 70.0.0.20240524",
@@ -188,8 +179,6 @@ strict = true
188179
module = [
189180
"async_solipsism",
190181
"async_solipsism.*",
191-
"grpc.aio",
192-
"grpc.aio.*",
193182
"mkdocs_macros.*",
194183
# The available stubs packages are outdated or incomplete (WIP/experimental):
195184
# https://github.com/frequenz-floss/frequenz-sdk-python/issues/430

src/frequenz/sdk/actor/power_distributing/_component_managers/_battery_manager.py

Lines changed: 25 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,14 @@
1010
import typing
1111
from datetime import timedelta
1212

13-
import grpc
1413
from frequenz.channels import Receiver, Sender
15-
from frequenz.client.microgrid import BatteryData, ComponentCategory, InverterData
14+
from frequenz.client.microgrid import (
15+
BatteryData,
16+
ClientError,
17+
ComponentCategory,
18+
InverterData,
19+
OperationOutOfRange,
20+
)
1621
from typing_extensions import override
1722

1823
from .... import microgrid
@@ -647,39 +652,38 @@ def _parse_result(
647652

648653
for inverter_id, aws in tasks.items():
649654
battery_ids = self._inv_bats_map[inverter_id]
655+
failed = True
650656
try:
651657
aws.result()
652-
except grpc.aio.AioRpcError as err:
653-
failed_power += distribution[inverter_id]
654-
failed_batteries = failed_batteries.union(battery_ids)
655-
if err.code() == grpc.StatusCode.OUT_OF_RANGE:
656-
_logger.debug(
657-
"Set power for battery %s failed, error %s",
658-
battery_ids,
659-
str(err),
660-
)
661-
else:
662-
_logger.warning(
663-
"Set power for battery %s failed, error %s. Mark it as broken.",
664-
battery_ids,
665-
str(err),
666-
)
658+
failed = False
659+
except OperationOutOfRange as err:
660+
_logger.debug(
661+
"Set power for battery %s failed due to out of range error: %s",
662+
battery_ids,
663+
err,
664+
)
665+
except ClientError as err:
666+
_logger.warning(
667+
"Set power for battery %s failed, mark it as broken. Error: %s",
668+
battery_ids,
669+
err,
670+
)
667671
except asyncio.exceptions.CancelledError:
668-
failed_power += distribution[inverter_id]
669-
failed_batteries = failed_batteries.union(battery_ids)
670672
_logger.warning(
671673
"Battery %s didn't respond in %f sec. Mark it as broken.",
672674
battery_ids,
673675
request_timeout.total_seconds(),
674676
)
675677
except Exception: # pylint: disable=broad-except
676-
failed_power += distribution[inverter_id]
677-
failed_batteries = failed_batteries.union(battery_ids)
678678
_logger.exception(
679679
"Unknown error while setting power to batteries: %s",
680680
battery_ids,
681681
)
682682

683+
if failed:
684+
failed_power += distribution[inverter_id]
685+
failed_batteries.update(battery_ids)
686+
683687
return failed_power, failed_batteries
684688

685689
async def _cancel_tasks(

src/frequenz/sdk/actor/power_distributing/_component_managers/_ev_charger_manager/_ev_charger_manager.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,13 @@
88
import logging
99
from datetime import datetime, timedelta, timezone
1010

11-
import grpc
1211
from frequenz.channels import Broadcast, Sender, merge, select, selected_from
13-
from frequenz.client.microgrid import ApiClient, ComponentCategory, EVChargerData
12+
from frequenz.client.microgrid import (
13+
ApiClient,
14+
ClientError,
15+
ComponentCategory,
16+
EVChargerData,
17+
)
1418
from typing_extensions import override
1519

1620
from frequenz.sdk import microgrid
@@ -335,9 +339,9 @@ async def _set_api_power(
335339
_logger.warning(
336340
"Timeout while setting power to EV charger %s", component_id
337341
)
338-
case grpc.aio.AioRpcError() as err:
342+
case ClientError() as err:
339343
_logger.warning(
340-
"Error while setting power to EV charger %s: %s",
344+
"Got a client error while setting power to EV charger %s: %s",
341345
component_id,
342346
err,
343347
)

src/frequenz/sdk/actor/power_distributing/_component_managers/_pv_inverter_manager/_pv_inverter_manager.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,13 @@
88
import logging
99
from datetime import timedelta
1010

11-
import grpc
1211
from frequenz.channels import Broadcast, Sender
13-
from frequenz.client.microgrid import ComponentCategory, InverterData, InverterType
12+
from frequenz.client.microgrid import (
13+
ClientError,
14+
ComponentCategory,
15+
InverterData,
16+
InverterType,
17+
)
1418
from typing_extensions import override
1519

1620
from ....._internal._channels import LatestValueCache
@@ -197,9 +201,9 @@ async def _set_api_power( # pylint: disable=too-many-locals
197201
_logger.warning(
198202
"Timeout while setting power to PV inverter %s", component_id
199203
)
200-
case grpc.aio.AioRpcError() as err:
204+
case ClientError() as err:
201205
_logger.warning(
202-
"Error while setting power to PV inverter %s: %s",
206+
"Got a client error while setting power to PV inverter %s: %s",
203207
component_id,
204208
err,
205209
)

0 commit comments

Comments
 (0)