Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 10 additions & 3 deletions RELEASE_NOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,25 @@

## Summary

<!-- Here goes a general summary of what this release is about -->
This release updates the `frequenz-api-dispatch` dependency to `v1.0.0-rc3` and adapts the client to the latest API changes. It introduces more specific component categories and new event names while maintaining backward compatibility.

## Upgrading

<!-- Here goes notes on how to upgrade from previous versions, including deprecations and what they should be replaced with -->
* `InverterType.SOLAR` is now deprecated in favor of `InverterType.PV`. The old name can still be used but will be removed in a future release.
* The following dependencies were updated:
* `frequenz-api-dispatch` to `v1.0.0-rc3`
* `frequenz-client-common` to `v0.3.6`
* `grpcio` to `v1.72.1`

## New Features

* **`ElectricalComponentCategory`**: The client now uses the more specific `frequenz.client.common.microgrid.electrical_components.ElectricalComponentCategory` for targeting components.
* The new property `TargetCategory.category2` will return an `ElectricalComponentCategory`.
* The existing `TargetCategory.category` property is preserved for backward compatibility and returns the corresponding `ComponentCategory`.
* Support secrets for signing and verifying messages.
* Use the new env variable `DISPATCH_API_SIGN_SECRET` to set the secret key.
* Use the new `sign_secret` parameter in the `DispatchClient` constructor to set the secret key.
* Added `auth_key` parameter to the `dispatch-cli` and thew env variable `DISPATCH_API_AUTH_KEY` to set the authentication key for the Dispatch API.
* Added `auth_key` parameter to the `dispatch-cli` and the new variable `DISPATCH_API_AUTH_KEY` to set the authentication key for the Dispatch API.


## Bug Fixes
Expand Down
12 changes: 6 additions & 6 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,11 @@ classifiers = [
requires-python = ">= 3.11, < 4"
dependencies = [
"typing-extensions >= 4.13.0, < 5",
"frequenz-api-dispatch == 1.0.0-rc2",
"frequenz-api-dispatch >= 1.0.0-rc3, < 2",
"frequenz-client-base >= 0.11.0, < 0.12.0",
"frequenz-client-common >= 0.3.2, < 0.4.0",
"frequenz-client-common >= 0.3.6, < 0.4.0",
"frequenz-core >= 1.0.2, < 2.0.0",
"grpcio >= 1.70.0, < 2",
"grpcio >= 1.72.1, < 2",
"python-dateutil >= 2.8.2, < 3.0",
]
dynamic = ["version"]
Expand All @@ -64,7 +64,7 @@ cli = [
dev-flake8 = [
"flake8 == 7.3.0",
"flake8-docstrings == 1.7.0",
"flake8-pyproject == 1.2.3", # For reading the flake8 config from pyproject.toml
"flake8-pyproject == 1.2.3", # For reading the flake8 config from pyproject.toml
"pydoclint == 0.6.6",
"pydocstyle == 6.3.0",
]
Expand All @@ -75,7 +75,7 @@ dev-mkdocs = [
"mike == 2.1.3",
"mkdocs-gen-files == 0.5.0",
"mkdocs-literate-nav == 0.6.2",
"frequenz-api-dispatch == 1.0.0-rc2",
"frequenz-api-dispatch == 1.0.0-rc3",
"mkdocs-macros-plugin == 1.3.7",
"mkdocs-material == 9.6.16",
"mkdocstrings[python] == 0.30.0",
Expand All @@ -95,7 +95,7 @@ dev-pylint = [
"pylint == 3.3.7",
# For checking the noxfile, docs/ script, and tests
"frequenz-client-dispatch[cli,dev-mkdocs,dev-noxfile,dev-pytest]",
"frequenz-api-dispatch == 1.0.0-rc2",
"frequenz-api-dispatch == 1.0.0-rc3",
]
dev-pytest = [
"pytest == 8.4.1",
Expand Down
15 changes: 13 additions & 2 deletions src/frequenz/client/dispatch/_cli_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@
from tzlocal import get_localzone

from frequenz.client.common.microgrid.components import ComponentCategory
from frequenz.client.common.microgrid.electrical_components import (
ElectricalComponentCategory,
)
from frequenz.client.dispatch.types import (
BatteryType,
EvChargerType,
Expand Down Expand Up @@ -177,9 +180,17 @@ def convert(

def enum_from_str(
name: str,
) -> InverterType | BatteryType | EvChargerType | ComponentCategory:
) -> (
InverterType
| BatteryType
| EvChargerType
| ElectricalComponentCategory
| ComponentCategory
):
"""Convert a string to an enum member."""
name = name.strip().upper()
if name in ElectricalComponentCategory.__members__:
return ElectricalComponentCategory[name]
if name in ComponentCategory.__members__:
return ComponentCategory[name]
if name in InverterType.__members__:
Expand Down Expand Up @@ -208,7 +219,7 @@ def enum_from_str(
"- METER,INVERTER # A list of component categories\n"
"- NA_ION,SOLAR # A list of component category types (category is derived)\n"
"Valid categories:\n"
f"{', '.join([cat.name for cat in ComponentCategory])}\n"
f"{', '.join([cat.name for cat in ElectricalComponentCategory])}\n"
"Valid types:\n"
f"{types_str}\n",
param,
Expand Down
38 changes: 26 additions & 12 deletions src/frequenz/client/dispatch/_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,15 @@
"""Dispatch API client for Python."""
from __future__ import annotations

import warnings
from datetime import datetime, timedelta
from typing import Any, AsyncIterator, Awaitable, Iterator, Literal, cast

# pylint: disable=no-name-in-module
from frequenz.api.common.v1.pagination.pagination_params_pb2 import PaginationParams
# pylint: disable-next=no-name-in-module
from frequenz.api.common.v1alpha8.pagination.pagination_params_pb2 import (
PaginationParams,
)
from frequenz.api.common.v1alpha8.types.interval_pb2 import Interval as PBInterval
from frequenz.api.dispatch.v1 import dispatch_pb2_grpc
from frequenz.api.dispatch.v1.dispatch_pb2 import (
CreateMicrogridDispatchResponse,
Expand All @@ -20,11 +24,6 @@
ListMicrogridDispatchesResponse,
StreamMicrogridDispatchesRequest,
StreamMicrogridDispatchesResponse,
)
from frequenz.api.dispatch.v1.dispatch_pb2 import (
TimeIntervalFilter as PBTimeIntervalFilter,
)
from frequenz.api.dispatch.v1.dispatch_pb2 import (
UpdateMicrogridDispatchRequest,
UpdateMicrogridDispatchResponse,
)
Expand Down Expand Up @@ -60,7 +59,8 @@ def __init__(
self,
*,
server_url: str,
auth_key: str,
auth_key: str | None = None,
key: str | None = None,
sign_secret: str | None = None,
connect: bool = True,
call_timeout: timedelta = timedelta(seconds=60),
Expand All @@ -71,11 +71,27 @@ def __init__(
Args:
server_url: The URL of the server to connect to.
auth_key: API key to use for authentication.
key: Deprecated, use `auth_key` instead.
sign_secret: Optional secret for signing requests.
connect: Whether to connect to the service immediately.
call_timeout: Timeout for gRPC calls, default is 60 seconds.
stream_timeout: Timeout for gRPC streams, default is 5 minutes.

Raises:
TypeError: If neither `auth_key` nor `key` is provided.
"""
if key is not None:
warnings.warn(
"The `key` parameter is deprecated, use `auth_key` instead.",
DeprecationWarning,
stacklevel=2,
)
auth_key = auth_key or key
if auth_key is None:
raise TypeError(
"__init__() missing 1 required keyword-only argument: 'auth_key'"
)

super().__init__(
server_url,
dispatch_pb2_grpc.MicrogridDispatchServiceStub,
Expand Down Expand Up @@ -170,11 +186,9 @@ async def list(

def to_interval(
from_: datetime | None, to: datetime | None
) -> PBTimeIntervalFilter | None:
) -> PBInterval | None:
return (
PBTimeIntervalFilter(
from_time=to_timestamp(from_), to_time=to_timestamp(to)
)
PBInterval(start_time=to_timestamp(from_), end_time=to_timestamp(to))
if from_ or to
else None
)
Expand Down
13 changes: 7 additions & 6 deletions src/frequenz/client/dispatch/test/_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
import grpc.aio

# pylint: disable=no-name-in-module
from frequenz.api.common.v1.pagination.pagination_info_pb2 import PaginationInfo
from frequenz.api.common.v1alpha8.pagination.pagination_info_pb2 import PaginationInfo
from frequenz.api.dispatch.v1.dispatch_pb2 import (
CreateMicrogridDispatchRequest as PBDispatchCreateRequest,
)
Expand All @@ -36,9 +36,10 @@
# pylint: enable=no-name-in-module
from frequenz.client.base.conversion import to_datetime as _to_dt
from frequenz.client.common.microgrid import MicrogridId
from frequenz.client.common.streaming import Event

from .._internal_types import DispatchCreateRequest
from ..types import Dispatch, DispatchEvent, DispatchId, Event
from ..types import Dispatch, DispatchEvent, DispatchId

_logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -148,20 +149,20 @@ def _filter_dispatch(
if target != dispatch.target:
return False
if _filter.HasField("start_time_interval"):
if start_from := _filter.start_time_interval.from_time:
if start_from := _filter.start_time_interval.start_time:
if dispatch.start_time < _to_dt(start_from):
return False
if start_to := _filter.start_time_interval.to_time:
if start_to := _filter.start_time_interval.end_time:
if dispatch.start_time >= _to_dt(start_to):
return False
if _filter.HasField("end_time_interval"):
if end_from := _filter.end_time_interval.from_time:
if end_from := _filter.end_time_interval.start_time:
if (
dispatch.duration
and dispatch.start_time + dispatch.duration < _to_dt(end_from)
):
return False
if end_to := _filter.end_time_interval.to_time:
if end_to := _filter.end_time_interval.end_time:
if (
dispatch.duration
and dispatch.start_time + dispatch.duration >= _to_dt(end_to)
Expand Down
14 changes: 8 additions & 6 deletions src/frequenz/client/dispatch/test/generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@
import random
from datetime import datetime, timedelta, timezone

from frequenz.client.common.microgrid.components import ComponentCategory
from frequenz.client.common.microgrid.electrical_components import (
ElectricalComponentCategory,
)

from .._internal_types import rounded_start_time
from ..recurrence import EndCriteria, Frequency, RecurrenceRule, Weekday
Expand Down Expand Up @@ -82,15 +84,15 @@ def generate_target_category_and_type(self) -> TargetCategory:
Returns:
a random category and type
"""
category = self._rng.choice(list(ComponentCategory)[1:])
category = self._rng.choice(list(ElectricalComponentCategory)[1:])
category_type: BatteryType | InverterType | EvChargerType | None = None

match category:
case ComponentCategory.BATTERY:
case ElectricalComponentCategory.BATTERY:
category_type = self._rng.choice(list(BatteryType)[1:])
case ComponentCategory.INVERTER:
case ElectricalComponentCategory.INVERTER:
category_type = self._rng.choice(list(InverterType)[1:])
case ComponentCategory.EV_CHARGER:
case ElectricalComponentCategory.EV_CHARGER:
category_type = self._rng.choice(list(EvChargerType)[1:])
case _:
category_type = None
Expand All @@ -116,7 +118,7 @@ def generate_dispatch(self) -> Dispatch:
*[
# Not yet used
# self.generate_target_category_and_type()
self._rng.choice(list(ComponentCategory)[1:])
self._rng.choice(list(ElectricalComponentCategory)[1:])
for _ in range(self._rng.randint(1, 10))
]
),
Expand Down
Loading