|
2 | 2 |
|
3 | 3 | ## Summary |
4 | 4 |
|
5 | | -This release is a major breaking change, as we jump to the API specification version 0.17.x, which introduces big and fundamental breaking changes. This also starts using the `v1` namespace in `frequenz-api-common`, which also introduces major breaking changes. It would be very hard to detail all the API changes here, please refer to the [Microgrid API releases](https://github.com/frequenz-floss/frequenz-api-microgrid/releases) and [Common API releases](https://github.com/frequenz-floss/frequenz-api-common/releases). |
| 5 | +This release is a major breaking change. The client now targets the Microgrid API specification version `0.18.x` and the `v1` namespace in `frequenz-api-common`. Both upstream projects introduce large structural and naming changes to components, metrics, and telemetry, and this client has been refactored accordingly. |
| 6 | + |
| 7 | +Existing code written for `frequenz-client-microgrid` `v0.9.1` will not work without changes. Upgrading will typically require: |
| 8 | + |
| 9 | +- Bumping dependencies to the new API and common libraries. |
| 10 | +- Updating imports for components, metrics, and IDs. |
| 11 | +- Migrating from the old ad-hoc component and sensor APIs to the new component/metrics model. |
| 12 | +- Adapting to the new power-control and bounds APIs. |
| 13 | + |
| 14 | +For a full overview of upstream changes, consult the [Microgrid API releases](https://github.com/frequenz-floss/frequenz-api-microgrid/releases) and [Common API releases](https://github.com/frequenz-floss/frequenz-api-common/releases). |
6 | 15 |
|
7 | 16 | ## Upgrading |
8 | 17 |
|
9 | | -- `MicrogridApiClient`: |
| 18 | +The following notes are aimed at users upgrading from `frequenz-client-microgrid` `v0.9.1`. |
| 19 | + |
| 20 | +### Dependencies and imports |
| 21 | + |
| 22 | +- **Dependencies**: |
| 23 | + |
| 24 | + - `frequenz-api-microgrid` is now required at `>= 0.18.0, < 0.19.0`. |
| 25 | + - `frequenz-api-common` is now required at `>= 0.8.0, < 1.0.0` and uses the `v1` namespace. |
| 26 | + - `frequenz-client-common` is now required at `>= 0.3.6, < 0.4.0` and provides ID and helper types used throughout the client. |
| 27 | + |
| 28 | + Make sure you pin compatible versions in your own project when upgrading. |
| 29 | + |
| 30 | +- **IDs and common types**: |
| 31 | + |
| 32 | + IDs come from `frequenz.client.common` (this was already true in `v0.9.1`, but they are now used more consistently): |
| 33 | + |
| 34 | + ```python |
| 35 | + from frequenz.client.common.microgrid import MicrogridId |
| 36 | + from frequenz.client.common.microgrid.components import ComponentId |
| 37 | + ``` |
| 38 | + |
| 39 | +- **Components and metrics**: |
| 40 | + |
| 41 | + The old component and data types (`Component`, `ComponentCategory`, `BatteryData`, `InverterData`, `ComponentState*`, etc.) that used to live directly under `frequenz.client.microgrid` have been replaced with a richer component and metrics model: |
| 42 | + |
| 43 | + ```python |
| 44 | + from frequenz.client.microgrid import MicrogridApiClient |
| 45 | + from frequenz.client.microgrid import component, metrics |
| 46 | + |
| 47 | + # Example component types |
| 48 | + from frequenz.client.microgrid.component import ( |
| 49 | + Component, |
| 50 | + ComponentCategory, |
| 51 | + ComponentConnection, |
| 52 | + ComponentDataSamples, |
| 53 | + ComponentStateSample, |
| 54 | + GridConnectionPoint, |
| 55 | + Inverter, |
| 56 | + Battery, |
| 57 | + ) |
| 58 | + |
| 59 | + # Metrics and bounds |
| 60 | + from frequenz.client.microgrid.metrics import Metric, Bounds, MetricSample |
| 61 | + ``` |
| 62 | + |
| 63 | + Update your imports to use these new modules instead of the removed legacy types. |
| 64 | + |
| 65 | +### Metadata: `metadata()` → `get_microgrid_info()` |
| 66 | + |
| 67 | +The old `metadata()` method has been replaced by `get_microgrid_info()` which returns a richer `MicrogridInfo` object. |
| 68 | + |
| 69 | +### Listing components and connections |
| 70 | + |
| 71 | +In `v0.9.1` you would often use: |
| 72 | + |
| 73 | +```python |
| 74 | +components = await client.components() |
| 75 | +connections = await client.connections(starts={component_id}, ends=set()) |
| 76 | +``` |
| 77 | + |
| 78 | +Now: |
| 79 | + |
| 80 | +- **List components**: |
| 81 | + |
| 82 | + ```python |
| 83 | + components = await client.list_components( |
| 84 | + components=[ComponentId(1), ComponentId(2)], |
| 85 | + categories=[ComponentCategory.INVERTER, ComponentCategory.BATTERY], |
| 86 | + ) |
| 87 | + ``` |
| 88 | + |
| 89 | + Notes: |
| 90 | + |
| 91 | + - `components` may contain `ComponentId` instances or `Component` objects. |
| 92 | + - `categories` may contain `ComponentCategory` enum values or raw integer category IDs. |
| 93 | + - Filters across `components` and `categories` are combined with `AND`; values inside each list are combined with `OR`. |
| 94 | + |
| 95 | +- **List connections**: |
| 96 | + |
| 97 | + ```python |
| 98 | + connections = await client.list_connections( |
| 99 | + sources=[ComponentId(1)], |
| 100 | + destinations=[ComponentId(2)], |
| 101 | + ) |
| 102 | + ``` |
| 103 | + |
| 104 | + Notes: |
| 105 | + |
| 106 | + - `sources` and `destinations` accept `ComponentId` or `Component` instances. |
| 107 | + - Filters across `sources` and `destinations` are combined with `AND`; values inside each list are combined with `OR`. |
| 108 | + - Connections now also use `.source` and `.destination` terminology instead of `.start` and `.end`. |
| 109 | + |
| 110 | + |
| 111 | +### Sensors: `list_sensors()`, `stream_sensor_data()` → *removed* (temporary) |
| 112 | + |
| 113 | +The old `list_sensors()` and `stream_sensor_data()` method has no direct equivalent. It will be reintroduced in a future release once sensor abstractions are reworked to fit the new component and metrics model. |
| 114 | + |
| 115 | +### Power control: `set_power()` / `set_reactive_power()` → `set_component_power_active()` / `set_component_power_reactive()` |
| 116 | + |
| 117 | +In `v0.9.1` you would typically set power using methods like: |
| 118 | + |
| 119 | +```python |
| 120 | +await client.set_power(component_id, power_w) |
| 121 | +await client.set_reactive_power(component_id, reactive_power_var) |
| 122 | +``` |
| 123 | + |
| 124 | +These methods have been replaced with lifetime-aware, metric-aligned calls: |
| 125 | + |
| 126 | +```python |
| 127 | +# Active power in watts |
| 128 | +expiry = await client.set_component_power_active( |
| 129 | + component=ComponentId(1), |
| 130 | + power_w=1_000.0, |
| 131 | + request_lifetime=timedelta(seconds=30), |
| 132 | +) |
| 133 | + |
| 134 | +# Reactive power in volt-ampere reactive (var) |
| 135 | +expiry = await client.set_component_power_reactive( |
| 136 | + component=ComponentId(1), |
| 137 | + power_var=500.0, |
| 138 | + request_lifetime=timedelta(seconds=30), |
| 139 | +) |
| 140 | +``` |
| 141 | + |
| 142 | +- Both methods accept either `ComponentId` or `Component` instances. |
| 143 | + |
| 144 | +### Bounds: `set_bounds()` → `add_component_bounds()` |
| 145 | + |
| 146 | +In `v0.9.1`, power bounds were earlier set using methods like `set_bounds(component_id, lower, upper)`. |
| 147 | + |
| 148 | +Now the new API reflects the `v0.18` metrics semantics: bounds are attached to metrics and transported as part of telemetry samples. Use `add_component_bounds()` together with `Metric` and `Bounds`: |
| 149 | + |
| 150 | +```python |
| 151 | +await client.add_component_bounds( |
| 152 | + component=ComponentId(1), |
| 153 | + target=Metric.ACTIVE_POWER, |
| 154 | + bounds=[Bounds(lower=-1_000.0, upper=1_000.0)], |
| 155 | +) |
| 156 | +``` |
| 157 | + |
| 158 | +Notes: |
| 159 | + |
| 160 | +- Bounds are now metric-specific: you must specify a `Metric` when adding bounds. |
| 161 | +- Bounds are represented as at most two ranges, matching `frequenz-api-common` `v1` (`Bounds` may contain up to two inclusive ranges). |
| 162 | + |
| 163 | +### Streaming telemetry: `*_data()` → `receive_component_data_samples_stream()` |
| 164 | + |
| 165 | +The streaming model changed significantly. |
| 166 | + |
| 167 | +In `v0.9.1`, you would use: |
| 168 | + |
| 169 | +```python |
| 170 | +receiver = await client.meter_data(component_id) |
| 171 | +async for sample in receiver: |
| 172 | + # sample is a MeterData instance |
| 173 | + ... |
| 174 | +``` |
| 175 | + |
| 176 | +Now, telemetry is integrated around components and metrics using `receive_component_data_samples_stream()` and `ComponentDataSamples`: |
| 177 | + |
| 178 | +```python |
| 179 | +receiver: Receiver[ComponentDataSamples] = ( |
| 180 | + await client.receive_component_data_samples_stream( |
| 181 | + component=ComponentId(1), |
| 182 | + metrics=[Metric.ACTIVE_POWER, Metric.REACTIVE_POWER], |
| 183 | + ) |
| 184 | +) |
| 185 | + |
| 186 | +async for samples in receiver: |
| 187 | + # Each `samples` corresponds to a single component at a single timestamp. |
| 188 | + # Metric values and bounds are attached per metric. |
| 189 | +``` |
| 190 | + |
| 191 | +The upstream Microgrid API `v0.18` changes how samples are structured; important points from the upstream migration notes (see `frequenz-api-microgrid` discussion #278): |
| 192 | + |
| 193 | +- Rated bounds moved into component metadata; telemetry samples now carry operational bounds per metric. |
| 194 | +- Old `component_bounds` and `system_{inclusion,exclusion}_bounds` are unified under `samples.metric[x].bounds`. |
| 195 | +- Older voltage metrics like `VOLTAGE_PHASE_A` map to `AC_VOLTAGE_PHASE_A_N` and similar; review metric names in `frequenz.client.microgrid.metrics.Metric` when porting code. |
| 196 | +- All metrics for a given component at a given time share the same `sampled_at` timestamp. |
| 197 | +- At most one `ComponentState` is included per `ComponentData`. |
| 198 | + |
| 199 | +When migrating: |
10 | 200 |
|
11 | | - * The client now follows the v0.17 API names, so most methods changed names and signatures. |
| 201 | +- Prefer requesting only the metrics you actually consume. |
| 202 | +- Use the new bounds representation instead of any previously maintained client-side bounds fields. |
| 203 | +- Replace sensor-centric streams with component-centric streams; each telemetry message now contains all requested metrics for a component. |
12 | 204 |
|
13 | 205 | ## New Features |
14 | 206 |
|
15 | | -<!-- Here goes the main new features and examples or instructions on how to use them --> |
| 207 | +- Add `get_microgrid_info()` returning a rich `MicrogridInfo` dataclass with ID, enterprise, location, delivery area, status, and timestamps. |
| 208 | +- Add a metrics model under `frequenz.client.microgrid.metrics` including the `Metric` enum, `Bounds`, and `MetricSample`/`AggregatedMetricValue`. |
| 209 | +- Add high-level methods on `MicrogridApiClient` for listing components and connections, adding component bounds, receiving component data samples streams, and controlling active/reactive power with lifetimes. |
16 | 210 |
|
17 | 211 | ## Bug Fixes |
18 | 212 |
|
19 | | -<!-- Here goes notable bug fixes that are worth a special mention or explanation --> |
| 213 | +- Restore missing `Metric` enum members to match the upstream common API definitions. |
| 214 | +- Remove an artificial timeout from the gRPC telemetry stream to avoid spurious cancellations under normal operation. |
| 215 | +- Align error handling and validation with the updated API behavior (for example, validating lifetimes and power ranges before sending control requests). |
0 commit comments