@@ -292,6 +292,89 @@ async def set_component_power_active( # noqa: DOC502 (raises ApiClientError ind
292292
293293 return None
294294
295+ async def set_component_power_reactive ( # noqa: DOC502 (raises ApiClientError indirectly)
296+ self ,
297+ component : ComponentId | Component ,
298+ power : float ,
299+ * ,
300+ request_lifetime : timedelta | None = None ,
301+ validate_arguments : bool = True ,
302+ ) -> datetime | None :
303+ """Set the reactive power output of a component.
304+
305+ We follow the polarity specified in the IEEE 1459-2010 standard
306+ definitions, where:
307+
308+ - Positive reactive is inductive (current is lagging the voltage)
309+ - Negative reactive is capacitive (current is leading the voltage)
310+
311+ The power output is specified in VAr.
312+
313+ The return value is the timestamp until which the given power command will
314+ stay in effect. After this timestamp, the component's reactive power will
315+ be set to 0, if the API receives no further command to change it before
316+ then. By default, this timestamp will be set to the current time plus 60
317+ seconds.
318+
319+ Note:
320+ The target component may have a resolution of more than 1 VAr. E.g., an
321+ inverter may have a resolution of 88 VAr. In such cases, the magnitude of
322+ power will be floored to the nearest multiple of the resolution.
323+
324+ Performs the following sequence actions for the following component
325+ categories:
326+
327+ * TODO document missing.
328+
329+ Args:
330+ component: The component to set the output reactive power of.
331+ power: The output reactive power level, in VAr. The standard of polarity is
332+ as per the IEEE 1459-2010 standard definitions: positive reactive is
333+ inductive (current is lagging the voltage); negative reactive is
334+ capacitive (current is leading the voltage).
335+ request_lifetime: The duration, until which the request will stay in effect.
336+ This duration has to be between 10 seconds and 15 minutes (including
337+ both limits), otherwise the request will be rejected. It has
338+ a resolution of a second, so fractions of a second will be rounded for
339+ `timedelta` objects, and it is interpreted as seconds for `int` objects.
340+ If not provided, it usually defaults to 60 seconds.
341+ validate_arguments: Whether to validate the arguments before sending the
342+ request. If `True` a `ValueError` will be raised if an argument is
343+ invalid without even sending the request to the server, if `False`, the
344+ request will be sent without validation.
345+
346+ Returns:
347+ The timestamp until which the given power command will stay in effect, or
348+ `None` if it was not provided.
349+
350+ Raises:
351+ ApiClientError: If the are any errors communicating with the Microgrid API,
352+ most likely a subclass of
353+ [GrpcError][frequenz.client.microgrid.GrpcError].
354+ """
355+ lifetime_seconds = _delta_to_seconds (request_lifetime )
356+
357+ if validate_arguments :
358+ _validate_set_power_args (power = power , request_lifetime = lifetime_seconds )
359+
360+ response = await client .call_stub_method (
361+ self ,
362+ lambda : self ._async_stub .SetComponentPowerReactive (
363+ microgrid_pb2 .SetComponentPowerReactiveRequest (
364+ component_id = _get_component_id (component ),
365+ power = power ,
366+ request_lifetime = lifetime_seconds ,
367+ ),
368+ timeout = int (DEFAULT_GRPC_CALL_TIMEOUT ),
369+ ),
370+ method_name = "SetComponentPowerReactive" ,
371+ )
372+
373+ if response .HasField ("valid_until" ):
374+ return conversion .to_datetime (response .valid_until )
375+
376+ return None
377+
295378
296379def _get_component_id (component : ComponentId | Component ) -> int :
297380 """Get the component ID from a component or component ID."""
0 commit comments