Skip to content

Commit 087c7fe

Browse files
committed
Upgrade to microgrid v0.18 / common v0.8
This commit updates the import and perform simple symbol renames, as well as adapting some structural changes. The interface is not affected, changes should be backwards compatible, although some minor behaviour changes might be present (for example responses of set_component_power_xxx()). The structural changes are: * set_component_power_active()/reactive() changed from unary-unary to unary-stream. For now we are only receiving the first response and returning that, but this will be improved in the future. * add_component_bounds() changed the Validity enum to have int values to cope with the more flexible API. In the future we'll add the possibility to pass arbitrary validities. * ComponentStateSample's errors and warnings are now wrapped in a message with multiple fields, for now we are only retrieving the code. In the future we'll wrap the new fields too. * MetricSample.connection is now also wrapped in a message with multiple fields. We are only getting the connection name for now, but we'll add the new information in the future too. * Some component categories were renamed, we added the new names but kept the old ones as deprecated. We needed to add the new names in this commit to avoid having to adapt the code too much, as the category name is tied to the category_specific_info.kind value, so we needed the new values. We need to disable the "unique" constraint for ComponentCategory temporarily to allow for the deprecated aliases. Other changes (and there are many pending) are left as future improvements. Some of these pending changes are: * Rename component -> electrical component (including IDs and fields) * Rename grid -> grid connection point * Rename voltage transformer -> power transformer * Rename relay -> breaker * Rename SOLAR -> PV * Rename source -> connection * Add new component categories, Metrics and other new enum fields * Deprecate UNDERVOLTAGE_SHUTDOWN and old Metric names * Rename category_speific_metadata -> category_specific_info * Rename sampled_at -> origin_time / sample_time Signed-off-by: Leandro Lucarella <[email protected]>
1 parent 7280c5e commit 087c7fe

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

57 files changed

+1042
-799
lines changed

src/frequenz/client/microgrid/_client.py

Lines changed: 114 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,17 @@
1414
from datetime import datetime, timedelta
1515
from typing import Any, assert_never
1616

17-
from frequenz.api.common.v1.metrics import bounds_pb2, metric_sample_pb2
18-
from frequenz.api.common.v1.microgrid.components import components_pb2
19-
from frequenz.api.microgrid.v1 import microgrid_pb2, microgrid_pb2_grpc
17+
from frequenz.api.common.v1alpha8.metrics import bounds_pb2, metrics_pb2
18+
from frequenz.api.common.v1alpha8.microgrid.electrical_components import (
19+
electrical_components_pb2,
20+
)
21+
from frequenz.api.microgrid.v1alpha18 import microgrid_pb2, microgrid_pb2_grpc
2022
from frequenz.channels import Receiver
2123
from frequenz.client.base import channel, client, conversion, retry, streaming
24+
from frequenz.client.base.exception import ApiClientError
2225
from frequenz.client.common.microgrid.components import ComponentId
2326
from google.protobuf.empty_pb2 import Empty
27+
from grpc.aio import AioRpcError
2428
from typing_extensions import override
2529

2630
from ._exception import ClientNotConnected
@@ -90,7 +94,8 @@ def __init__(
9094
self._component_data_broadcasters: dict[
9195
str,
9296
streaming.GrpcStreamBroadcaster[
93-
microgrid_pb2.ReceiveComponentDataStreamResponse, ComponentDataSamples
97+
microgrid_pb2.ReceiveElectricalComponentTelemetryStreamResponse,
98+
ComponentDataSamples,
9499
],
95100
] = {}
96101
self._sensor_data_broadcasters: dict[
@@ -165,10 +170,7 @@ async def get_microgrid_info( # noqa: DOC502 (raises ApiClientError indirectly)
165170
"""
166171
response = await client.call_stub_method(
167172
self,
168-
lambda: self.stub.GetMicrogridMetadata(
169-
Empty(),
170-
timeout=DEFAULT_GRPC_CALL_TIMEOUT,
171-
),
173+
lambda: self.stub.GetMicrogrid(Empty(), timeout=DEFAULT_GRPC_CALL_TIMEOUT),
172174
method_name="GetMicrogridMetadata",
173175
)
174176

@@ -217,17 +219,19 @@ async def list_components( # noqa: DOC502 (raises ApiClientError indirectly)
217219
"""
218220
response = await client.call_stub_method(
219221
self,
220-
lambda: self.stub.ListComponents(
221-
microgrid_pb2.ListComponentsRequest(
222-
component_ids=map(_get_component_id, components),
223-
categories=map(_get_category_value, categories),
222+
lambda: self.stub.ListElectricalComponents(
223+
microgrid_pb2.ListElectricalComponentsRequest(
224+
electrical_component_ids=map(_get_component_id, components),
225+
electrical_component_categories=map(
226+
_get_category_value, categories
227+
),
224228
),
225229
timeout=DEFAULT_GRPC_CALL_TIMEOUT,
226230
),
227231
method_name="ListComponents",
228232
)
229233

230-
return map(component_from_proto, response.components)
234+
return map(component_from_proto, response.electrical_components)
231235

232236
async def list_connections( # noqa: DOC502 (raises ApiClientError indirectly)
233237
self,
@@ -271,10 +275,12 @@ async def list_connections( # noqa: DOC502 (raises ApiClientError indirectly)
271275
"""
272276
response = await client.call_stub_method(
273277
self,
274-
lambda: self.stub.ListConnections(
275-
microgrid_pb2.ListConnectionsRequest(
276-
starts=map(_get_component_id, sources),
277-
ends=map(_get_component_id, destinations),
278+
lambda: self.stub.ListElectricalComponentConnections(
279+
microgrid_pb2.ListElectricalComponentConnectionsRequest(
280+
source_electrical_component_ids=map(_get_component_id, sources),
281+
destination_electrical_component_ids=map(
282+
_get_component_id, destinations
283+
),
278284
),
279285
timeout=DEFAULT_GRPC_CALL_TIMEOUT,
280286
),
@@ -283,11 +289,19 @@ async def list_connections( # noqa: DOC502 (raises ApiClientError indirectly)
283289

284290
return (
285291
conn
286-
for conn in map(component_connection_from_proto, response.connections)
292+
for conn in map(
293+
component_connection_from_proto,
294+
response.electrical_component_connections,
295+
)
287296
if conn is not None
288297
)
289298

290-
async def set_component_power_active( # noqa: DOC502 (raises ApiClientError indirectly)
299+
# pylint: disable-next=fixme
300+
# TODO: Unifi set_component_power_active and set_component_power_reactive, or at
301+
# least use a common implementation.
302+
# Return an iterator or receiver with the streamed responses instead of
303+
# returning just the first one
304+
async def set_component_power_active( # noqa: DOC503
291305
self,
292306
component: ComponentId | Component,
293307
power: float,
@@ -341,25 +355,37 @@ async def set_component_power_active( # noqa: DOC502 (raises ApiClientError ind
341355
if validate_arguments:
342356
_validate_set_power_args(power=power, request_lifetime=lifetime_seconds)
343357

344-
response = await client.call_stub_method(
345-
self,
346-
lambda: self.stub.SetComponentPowerActive(
347-
microgrid_pb2.SetComponentPowerActiveRequest(
348-
component_id=_get_component_id(component),
349-
power=power,
350-
request_lifetime=lifetime_seconds,
351-
),
352-
timeout=DEFAULT_GRPC_CALL_TIMEOUT,
353-
),
354-
method_name="SetComponentPowerActive",
355-
)
358+
method_name = "SetElectricalComponentPower"
359+
if not self.is_connected:
360+
raise ClientNotConnected(server_url=self.server_url, operation=method_name)
361+
362+
try:
363+
response = await anext(
364+
aiter(
365+
self.stub.SetElectricalComponentPower(
366+
microgrid_pb2.SetElectricalComponentPowerRequest(
367+
electrical_component_id=_get_component_id(component),
368+
power_type=microgrid_pb2.POWER_TYPE_ACTIVE,
369+
power=power,
370+
request_lifetime=lifetime_seconds,
371+
),
372+
timeout=DEFAULT_GRPC_CALL_TIMEOUT,
373+
)
374+
)
375+
)
376+
except AioRpcError as grpc_error:
377+
raise ApiClientError.from_grpc_error(
378+
server_url=self.server_url,
379+
operation=method_name,
380+
grpc_error=grpc_error,
381+
) from grpc_error
356382

357-
if response.HasField("valid_until"):
358-
return conversion.to_datetime(response.valid_until)
383+
if response.HasField("valid_until_time"):
384+
return conversion.to_datetime(response.valid_until_time)
359385

360386
return None
361387

362-
async def set_component_power_reactive( # noqa: DOC502 (raises ApiClientError indirectly)
388+
async def set_component_power_reactive( # noqa: DOC503
363389
self,
364390
component: ComponentId | Component,
365391
power: float,
@@ -419,21 +445,33 @@ async def set_component_power_reactive( # noqa: DOC502 (raises ApiClientError i
419445
if validate_arguments:
420446
_validate_set_power_args(power=power, request_lifetime=lifetime_seconds)
421447

422-
response = await client.call_stub_method(
423-
self,
424-
lambda: self.stub.SetComponentPowerReactive(
425-
microgrid_pb2.SetComponentPowerReactiveRequest(
426-
component_id=_get_component_id(component),
427-
power=power,
428-
request_lifetime=lifetime_seconds,
429-
),
430-
timeout=DEFAULT_GRPC_CALL_TIMEOUT,
431-
),
432-
method_name="SetComponentPowerReactive",
433-
)
448+
method_name = "SetElectricalComponentPower"
449+
if not self.is_connected:
450+
raise ClientNotConnected(server_url=self.server_url, operation=method_name)
434451

435-
if response.HasField("valid_until"):
436-
return conversion.to_datetime(response.valid_until)
452+
try:
453+
response = await anext(
454+
aiter(
455+
self.stub.SetElectricalComponentPower(
456+
microgrid_pb2.SetElectricalComponentPowerRequest(
457+
electrical_component_id=_get_component_id(component),
458+
power_type=microgrid_pb2.POWER_TYPE_REACTIVE,
459+
power=power,
460+
request_lifetime=lifetime_seconds,
461+
),
462+
timeout=DEFAULT_GRPC_CALL_TIMEOUT,
463+
)
464+
)
465+
)
466+
except AioRpcError as grpc_error:
467+
raise ApiClientError.from_grpc_error(
468+
server_url=self.server_url,
469+
operation=method_name,
470+
grpc_error=grpc_error,
471+
) from grpc_error
472+
473+
if response.HasField("valid_until_time"):
474+
return conversion.to_datetime(response.valid_until_time)
437475

438476
return None
439477

@@ -506,14 +544,11 @@ async def add_component_bounds( # noqa: DOC502 (Raises ApiClientError indirectl
506544
most likely a subclass of
507545
[GrpcError][frequenz.client.microgrid.GrpcError].
508546
"""
509-
extra_args = {}
510-
if validity is not None:
511-
extra_args["validity_duration"] = validity.value
512547
response = await client.call_stub_method(
513548
self,
514-
lambda: self.stub.AddComponentBounds(
515-
microgrid_pb2.AddComponentBoundsRequest(
516-
component_id=_get_component_id(component),
549+
lambda: self.stub.AugmentElectricalComponentBounds(
550+
microgrid_pb2.AugmentElectricalComponentBoundsRequest(
551+
electrical_component_id=_get_component_id(component),
517552
target_metric=_get_metric_value(target),
518553
bounds=(
519554
bounds_pb2.Bounds(
@@ -522,15 +557,15 @@ async def add_component_bounds( # noqa: DOC502 (Raises ApiClientError indirectl
522557
)
523558
for bound in bounds
524559
),
525-
**extra_args,
560+
request_lifetime=validity.value if validity else None,
526561
),
527562
timeout=DEFAULT_GRPC_CALL_TIMEOUT,
528563
),
529564
method_name="AddComponentBounds",
530565
)
531566

532-
if response.HasField("ts"):
533-
return conversion.to_datetime(response.ts)
567+
if response.HasField("valid_until_time"):
568+
return conversion.to_datetime(response.valid_until_time)
534569

535570
return None
536571

@@ -578,48 +613,43 @@ def receive_component_data_samples_stream(
578613
stream_name = f"microgrid-client-{client_id}-component-data-{key}"
579614
# Alias to avoid too long lines linter errors
580615
# pylint: disable-next=invalid-name
581-
Request = microgrid_pb2.ReceiveComponentDataStreamRequest
616+
Request = microgrid_pb2.ReceiveElectricalComponentTelemetryStreamRequest
582617
broadcaster = streaming.GrpcStreamBroadcaster(
583618
stream_name,
584619
lambda: aiter(
585-
self.stub.ReceiveComponentDataStream(
620+
self.stub.ReceiveElectricalComponentTelemetryStream(
586621
Request(
587-
component_id=_get_component_id(component),
588-
filter=Request.ComponentDataStreamFilter(
622+
electrical_component_id=_get_component_id(component),
623+
filter=Request.ComponentTelemetryStreamFilter(
589624
metrics=metrics_set
590625
),
591626
),
592627
timeout=DEFAULT_GRPC_CALL_TIMEOUT,
593628
)
594629
),
595-
lambda msg: component_data_samples_from_proto(msg.data),
630+
lambda msg: component_data_samples_from_proto(msg.telemetry),
596631
retry_strategy=self._retry_strategy,
597632
)
598633
self._component_data_broadcasters[key] = broadcaster
599634
return broadcaster.new_receiver(maxsize=buffer_size)
600635

601636

637+
# pylint: disable-next=fixme
638+
# TODO: Remove this enum, now AugmentElectricalComponentBounds takes a simple timeout as
639+
# an int.
602640
class Validity(enum.Enum):
603641
"""The duration for which a given list of bounds will stay in effect."""
604642

605-
FIVE_SECONDS = (
606-
microgrid_pb2.ComponentBoundsValidityDuration.COMPONENT_BOUNDS_VALIDITY_DURATION_5_SECONDS
607-
)
643+
FIVE_SECONDS = 5
608644
"""The bounds will stay in effect for 5 seconds."""
609645

610-
ONE_MINUTE = (
611-
microgrid_pb2.ComponentBoundsValidityDuration.COMPONENT_BOUNDS_VALIDITY_DURATION_1_MINUTE
612-
)
646+
ONE_MINUTE = 60
613647
"""The bounds will stay in effect for 1 minute."""
614648

615-
FIVE_MINUTES = (
616-
microgrid_pb2.ComponentBoundsValidityDuration.COMPONENT_BOUNDS_VALIDITY_DURATION_5_MINUTES
617-
)
649+
FIVE_MINUTES = 60 * 5
618650
"""The bounds will stay in effect for 5 minutes."""
619651

620-
FIFTEEN_MINUTES = (
621-
microgrid_pb2.ComponentBoundsValidityDuration.COMPONENT_BOUNDS_VALIDITY_DURATION_15_MINUTES
622-
)
652+
FIFTEEN_MINUTES = 60 * 15
623653
"""The bounds will stay in effect for 15 minutes."""
624654

625655

@@ -634,26 +664,30 @@ def _get_component_id(component: ComponentId | Component) -> int:
634664
assert_never(unexpected)
635665

636666

637-
def _get_metric_value(metric: Metric | int) -> metric_sample_pb2.Metric.ValueType:
667+
def _get_metric_value(metric: Metric | int) -> metrics_pb2.Metric.ValueType:
638668
"""Get the metric ID from a metric or metric ID."""
639669
match metric:
640670
case Metric():
641-
return metric_sample_pb2.Metric.ValueType(metric.value)
671+
return metrics_pb2.Metric.ValueType(metric.value)
642672
case int():
643-
return metric_sample_pb2.Metric.ValueType(metric)
673+
return metrics_pb2.Metric.ValueType(metric)
644674
case unexpected:
645675
assert_never(unexpected)
646676

647677

648678
def _get_category_value(
649679
category: ComponentCategory | int,
650-
) -> components_pb2.ComponentCategory.ValueType:
680+
) -> electrical_components_pb2.ElectricalComponentCategory.ValueType:
651681
"""Get the category value from a component or component category."""
652682
match category:
653683
case ComponentCategory():
654-
return components_pb2.ComponentCategory.ValueType(category.value)
684+
return electrical_components_pb2.ElectricalComponentCategory.ValueType(
685+
category.value
686+
)
655687
case int():
656-
return components_pb2.ComponentCategory.ValueType(category)
688+
return electrical_components_pb2.ElectricalComponentCategory.ValueType(
689+
category
690+
)
657691
case unexpected:
658692
assert_never(unexpected)
659693

src/frequenz/client/microgrid/_delivery_area.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import enum
77
from dataclasses import dataclass
88

9-
from frequenz.api.common.v1.grid import delivery_area_pb2
9+
from frequenz.api.common.v1alpha8.grid import delivery_area_pb2
1010

1111

1212
@enum.unique

src/frequenz/client/microgrid/_delivery_area_proto.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
import logging
77

8-
from frequenz.api.common.v1.grid import delivery_area_pb2
8+
from frequenz.api.common.v1alpha8.grid import delivery_area_pb2
99

1010
from ._delivery_area import DeliveryArea, EnergyMarketCodeType
1111
from ._util import enum_from_proto

src/frequenz/client/microgrid/_lifetime_proto.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
"""Loading of Lifetime objects from protobuf messages."""
55

6-
from frequenz.api.common.v1.microgrid import lifetime_pb2
6+
from frequenz.api.common.v1alpha8.microgrid import lifetime_pb2
77
from frequenz.client.base.conversion import to_datetime
88

99
from ._lifetime import Lifetime

src/frequenz/client/microgrid/_location_proto.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
import logging
77

8-
from frequenz.api.common.v1 import location_pb2
8+
from frequenz.api.common.v1alpha8.types import location_pb2
99

1010
from ._location import Location
1111

src/frequenz/client/microgrid/_microgrid_info.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
from dataclasses import dataclass
1010
from functools import cached_property
1111

12-
from frequenz.api.common.v1.microgrid import microgrid_pb2
12+
from frequenz.api.common.v1alpha8.microgrid import microgrid_pb2
1313
from frequenz.client.common.microgrid import EnterpriseId, MicrogridId
1414

1515
from ._delivery_area import DeliveryArea

src/frequenz/client/microgrid/_microgrid_info_proto.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
import logging
88

9-
from frequenz.api.common.v1.microgrid import microgrid_pb2
9+
from frequenz.api.common.v1alpha8.microgrid import microgrid_pb2
1010
from frequenz.client.base import conversion
1111
from frequenz.client.common.microgrid import EnterpriseId, MicrogridId
1212

0 commit comments

Comments
 (0)