1414from datetime import datetime , timedelta
1515from 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
2022from frequenz .channels import Receiver
2123from frequenz .client .base import channel , client , conversion , retry , streaming
24+ from frequenz .client .base .exception import ApiClientError
2225from frequenz .client .common .microgrid .components import ComponentId
2326from google .protobuf .empty_pb2 import Empty
27+ from grpc .aio import AioRpcError
2428from typing_extensions import override
2529
2630from ._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.
602640class 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
648678def _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
0 commit comments