|
2 | 2 |
|
3 | 3 | ## Summary |
4 | 4 |
|
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). |
| 5 | +This release adds a new `WindTurbine` component type. |
15 | 6 |
|
16 | 7 | ## Upgrading |
17 | 8 |
|
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: |
200 | | - |
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. |
| 9 | +- If you are using `match` and doing exhaustive matching on the `Component` types, you will get `mypy` errors and will need to handle the new `WindTurbine` type. |
204 | 10 |
|
205 | 11 | ## New Features |
206 | 12 |
|
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. |
210 | 13 | - Add `WindTurbine` component type. |
211 | | - |
212 | | -## Bug Fixes |
213 | | - |
214 | | -- Restore missing `Metric` enum members to match the upstream common API definitions. |
215 | | -- Remove an artificial timeout from the gRPC telemetry stream to avoid spurious cancellations under normal operation. |
216 | | -- Align error handling and validation with the updated API behavior (for example, validating lifetimes and power ranges before sending control requests). |
0 commit comments