Skip to content

Releases: frequenz-floss/frequenz-client-microgrid-python

v0.18.2

19 Dec 08:54
Immutable release. Only release title and notes can be modified.
v0.18.2
f70f903

Choose a tag to compare

Frequenz Microgrid API Client Release Notes

Summary

This release reintroduces sensor support that was temporarily removed in the v0.18.0 release. The new sensor API has been redesigned to fit the updated component and metrics model introduced in v0.18.0.

New Features

  • New sensor module (frequenz.client.microgrid.sensor) with sensor related types.

  • New MicrogridApiClient methods

    • list_sensors(): fetch sensor metadata.
    • receive_sensor_telemetry_stream(): stream sensor telemetry data.

Example:

import asyncio
from frequenz.client.microgrid import MicrogridApiClient
from frequenz.client.microgrid.metrics import Metric

URL = "grpc://[::1]:62060"

async def main() -> None:
    print(f"Connecting to {URL}...")
    async with MicrogridApiClient(URL) as client:
        print("Listing available sensors...")
        sensors = list(await client.list_sensors())

        if not sensors:
            print("No sensors found.")
            return

        print(f"Found {len(sensors)}: {sensors}.")
        print()

        sensor = sensors[0]
        print(f"Streaming telemetry from sensor {sensor.id} ({sensor.name})...")
        telemetry_stream = client.receive_sensor_telemetry_stream(
            sensors[0].id, list(Metric)
        )
        async for telemetry in telemetry_stream:
            print(f"\tReceived: {telemetry}")

asyncio.run(main())

Upgrading (from v0.9)

Sensor support restored with new API

Sensor support that was removed in v0.18.0 is now back, but with a redesigned API that aligns with the v0.18.0 component and metrics model.

list_sensors()

The method name remains the same, but the signature and return type have changed:

# Old v0.9.1 API
sensors: Iterable[Sensor] = await client.list_sensors()

# New v0.18.2 API (same method name, different types)
from frequenz.client.common.microgrid.sensors import SensorId
from frequenz.client.microgrid.sensor import Sensor

sensors: Iterable[Sensor] = await client.list_sensors()

# You can also filter by sensor IDs
sensors = await client.list_sensors(sensors=[SensorId(1), SensorId(2)])

The Sensor class now provides a new attribute microgrid_id: MicrogridId and the identity property now returns a tuple (SensorId, MicrogridId) instead of just SensorId.

stream_sensor_data()receive_sensor_telemetry_stream()

The streaming method has been renamed and its return type changed:

# Old v0.9.1 API
from frequenz.client.microgrid.sensor import SensorDataSamples, SensorMetric

receiver: Receiver[SensorDataSamples] = client.stream_sensor_data(
    sensor=SensorId(1),
    metrics=[SensorMetric.TEMPERATURE, SensorMetric.HUMIDITY],  # optional
)

async for samples in receiver:
    # samples.metric_samples, samples.state_sample, etc.
    ...

# New v0.18.2 API
from frequenz.client.microgrid.sensor import SensorTelemetry
from frequenz.client.microgrid.metrics import Metric

receiver: Receiver[SensorTelemetry] = client.receive_sensor_telemetry_stream(
    sensor=SensorId(1),
    metrics=[Metric.SENSOR_TEMPERATURE, Metric.AC_VOLTAGE],  # required
)

async for telemetry in receiver:
    # telemetry.sensor_id: SensorId
    # telemetry.metric_samples: Sequence[MetricSample]
    # telemetry.state_snapshots: Sequence[SensorStateSnapshot]
    for sample in telemetry.metric_samples:
        print(f"{sample.metric}: {sample.value} at {sample.sampled_at}")
    ...

Key differences:

  • Method renamed: stream_sensor_data()receive_sensor_telemetry_stream()
  • Metrics parameter is now required: You must specify which metrics to stream. The old API allowed None to stream all metrics.
  • Uses unified Metric enum: The old SensorMetric enum is removed. Use frequenz.client.microgrid.metrics.Metric instead.
  • Return type changed: SensorDataSamplesSensorTelemetry
  • State samples changed: SensorStateSampleSensorStateSnapshot with different structure (see below)

Sensor state types

The sensor state types have been redesigned:

Old v0.9.1 type New v0.18.2 type
SensorMetric Removed — use Metric
SensorStateCode SensorStateCode (different values)
SensorErrorCode SensorDiagnosticCode
SensorStateSample SensorStateSnapshot
SensorMetricSample MetricSample
SensorDataSamples SensorTelemetry

The new SensorStateSnapshot structure:

@dataclass(frozen=True, kw_only=True)
class SensorStateSnapshot:
    origin_time: datetime          # was `sampled_at`
    states: Set[SensorStateCode | int]  # was `frozenset`
    warnings: Sequence[SensorDiagnostic]  # new
    errors: Sequence[SensorDiagnostic]    # replaces error codes

The new SensorDiagnostic provides richer error/warning information:

@dataclass(frozen=True, kw_only=True)
class SensorDiagnostic:
    diagnostic_code: SensorDiagnosticCode | int
    message: str | None
    vendor_diagnostic_code: str | None

Import changes

Update your imports for sensor types:

# Old v0.9.1
from frequenz.client.microgrid.sensor import (
    Sensor,
    SensorDataSamples,
    SensorErrorCode,
    SensorMetric,
    SensorMetricSample,
    SensorStateCode,
    SensorStateSample,
)

# New v0.18.2
from frequenz.client.microgrid.sensor import (
    Sensor,
    SensorDiagnostic,
    SensorDiagnosticCode,
    SensorStateCode,
    SensorStateSnapshot,
    SensorTelemetry,
)
from frequenz.client.microgrid.metrics import Metric, MetricSample
from frequenz.client.common.microgrid.sensors import SensorId

What's Changed

Full Changelog: v0.18.1...v0.18.2

v0.18.1

11 Dec 10:15
Immutable release. Only release title and notes can be modified.
v0.18.1
5173e73

Choose a tag to compare

Frequenz Microgrid API Client Release Notes

Summary

This release adds a new WindTurbine component type.

Upgrading

  • 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.

New Features

  • Add WindTurbine component type.

What's Changed

New Contributors

Full Changelog: v0.18.0...v0.18.1

v0.19.0

10 Dec 15:49
Immutable release. Only release title and notes can be modified.
v0.19.0
0a43d72

Choose a tag to compare

v0.19.0 Pre-release
Pre-release

Frequenz Microgrid API Client Release Notes

Warning

This release was supposed to be v0.18.1, please don't use it. Use v0.18.1 instead.

v0.18.0

19 Nov 08:48
Immutable release. Only release title and notes can be modified.
v0.18.0
0bb5338

Choose a tag to compare

Frequenz Microgrid API Client Release Notes

Summary

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.

Existing code written for frequenz-client-microgrid v0.9.1 will not work without changes. Upgrading will typically require:

  • Bumping dependencies to the new API and common libraries.
  • Updating imports for components, metrics, and IDs.
  • Migrating from the old ad-hoc component and sensor APIs to the new component/metrics model.
  • Adapting to the new power-control and bounds APIs.

For a full overview of upstream changes, consult the Microgrid API releases and Common API releases.

Upgrading

The following notes are aimed at users upgrading from frequenz-client-microgrid v0.9.1.

Dependencies and imports

  • Dependencies:

    • frequenz-api-microgrid is now required at >= 0.18.0, < 0.19.0.
    • frequenz-api-common is now required at >= 0.8.0, < 1.0.0 and uses the v1 namespace.
    • frequenz-client-common is now required at >= 0.3.6, < 0.4.0 and provides ID and helper types used throughout the client.

    Make sure you pin compatible versions in your own project when upgrading.

  • IDs and common types:

    IDs come from frequenz.client.common (this was already true in v0.9.1, but they are now used more consistently):

    from frequenz.client.common.microgrid import MicrogridId
    from frequenz.client.common.microgrid.components import ComponentId
  • Components and metrics:

    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:

    from frequenz.client.microgrid import MicrogridApiClient
    from frequenz.client.microgrid import component, metrics
    
    # Example component types
    from frequenz.client.microgrid.component import (
        Component,
        ComponentCategory,
        ComponentConnection,
        ComponentDataSamples,
        ComponentStateSample,
        GridConnectionPoint,
        Inverter,
        Battery,
    )
    
    # Metrics and bounds
    from frequenz.client.microgrid.metrics import Metric, Bounds, MetricSample

    Update your imports to use these new modules instead of the removed legacy types.

Metadata: metadata()get_microgrid_info()

The old metadata() method has been replaced by get_microgrid_info() which returns a richer MicrogridInfo object.

Listing components and connections

In v0.9.1 you would often use:

components = await client.components()
connections = await client.connections(starts={component_id}, ends=set())

Now:

  • List components:

    components = await client.list_components(
        components=[ComponentId(1), ComponentId(2)],
        categories=[ComponentCategory.INVERTER, ComponentCategory.BATTERY],
    )

    Notes:

    • components may contain ComponentId instances or Component objects.
    • categories may contain ComponentCategory enum values or raw integer category IDs.
    • Filters across components and categories are combined with AND; values inside each list are combined with OR.
  • List connections:

    connections = await client.list_connections(
        sources=[ComponentId(1)],
        destinations=[ComponentId(2)],
    )

    Notes:

    • sources and destinations accept ComponentId or Component instances.
    • Filters across sources and destinations are combined with AND; values inside each list are combined with OR.
    • Connections now also use .source and .destination terminology instead of .start and .end.

Sensors: list_sensors(), stream_sensor_data()removed (temporary)

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.

Power control: set_power() / set_reactive_power()set_component_power_active() / set_component_power_reactive()

In v0.9.1 you would typically set power using methods like:

await client.set_power(component_id, power_w)
await client.set_reactive_power(component_id, reactive_power_var)

These methods have been replaced with lifetime-aware, metric-aligned calls:

# Active power in watts
expiry = await client.set_component_power_active(
    component=ComponentId(1),
    power_w=1_000.0,
    request_lifetime=timedelta(seconds=30),
)

# Reactive power in volt-ampere reactive (var)
expiry = await client.set_component_power_reactive(
    component=ComponentId(1),
    power_var=500.0,
    request_lifetime=timedelta(seconds=30),
)
  • Both methods accept either ComponentId or Component instances.

Bounds: set_bounds()add_component_bounds()

In v0.9.1, power bounds were earlier set using methods like set_bounds(component_id, lower, upper).

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:

await client.add_component_bounds(
    component=ComponentId(1),
    target=Metric.ACTIVE_POWER,
    bounds=[Bounds(lower=-1_000.0, upper=1_000.0)],
)

Notes:

  • Bounds are now metric-specific: you must specify a Metric when adding bounds.
  • Bounds are represented as at most two ranges, matching frequenz-api-common v1 (Bounds may contain up to two inclusive ranges).

Streaming telemetry: *_data()receive_component_data_samples_stream()

The streaming model changed significantly.

In v0.9.1, you would use:

receiver = await client.meter_data(component_id)
async for sample in receiver:
    # sample is a MeterData instance
    ...

Now, telemetry is integrated around components and metrics using receive_component_data_samples_stream() and ComponentDataSamples:

receiver: Receiver[ComponentDataSamples] = (
    await client.receive_component_data_samples_stream(
        component=ComponentId(1),
        metrics=[Metric.ACTIVE_POWER, Metric.REACTIVE_POWER],
    )
)

async for samples in receiver:
    # Each `samples` corresponds to a single component at a single timestamp.
    # Metric values and bounds are attached per metric.

The upstream Microgrid API v0.18 changes how samples are structured; important points from the upstream migration notes (see frequenz-api-microgrid discussion #278):

  • Rated bounds moved into component metadata; telemetry samples now carry operational bounds per metric.
  • Old component_bounds and system_{inclusion,exclusion}_bounds are unified under samples.metric[x].bounds.
  • 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.
  • All metrics for a given component at a given time share the same sampled_at timestamp.
  • At most one ComponentState is included per ComponentData.

When migrating:

  • Prefer requesting only the metrics you actually consume.
  • Use the new bounds representation instead of any previously maintained client-side bounds fields.
  • Replace sensor-centric streams with component-centric streams; each telemetry message now contains all requested metrics for a component.

New Features

  • Add get_microgrid_info() returning a rich MicrogridInfo dataclass with ID, enterprise, location, delivery area, status, and timestamps.
  • Add a metrics model under frequenz.client.microgrid.metrics including the Metric enum, Bounds, and MetricSample/AggregatedMetricValue.
  • 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.

Bug Fixes

  • Restore missing Metric enum members to match the upstream common API definitions.
  • Remove an artificial timeout from the gRPC telemetry stream to avoid spurious cancellations under normal operation.
  • Align error handling and validation with the updated API behavior (for example, validating lifetimes and power ranges before sending control requests).

What's Changed

  • Initial upgrade to the API v0.17.x by @llucax in #94
  • Add gRPC calls to control components by @llucax in #158
  • Implement ListComponents by @llucax in #165
  • Implement ListConnections by @llucax in #167
  • Clear release notes by @llucax in #177
  • Rename objects returned by calls to response internally by @llucax in #179
  • Implement ReceiveComponentDataStreamRequest by @llucax in #178
  • Bump the patch group with 3 updates by @dependabot[bot] in #185
  • Bump types-markdown from 3.8.0.20250708 to 3.8.0.20250809 by @dependabot[bot] in #187
  • Bump mkdocstrings-python from 1.16.12 to 1.18.2 in the mkdocstrings grou...
Read more

v0.9.1

21 Aug 13:14
v0.9.1
c025df1

Choose a tag to compare

Frequenz Microgrid API Client Release Notes

Summary

This release removes the timezonefinder dependency to significantly reduce package size by 66M+ and enable ARM platform support.

Warning

This is a breaking change shipped in a patch release because this feature has no known users.

Upgrading

The Location.timezone field no longer performs automatic timezone lookup from latitude/longitude coordinates.

# Automatic timezone lookup (no longer works)
location = Location(latitude=52.52, longitude=13.405)
print(location.timezone)  # Previously: ZoneInfo('Europe/Berlin'), now None

If you need timezone lookup from coordinates, install timezonefinder separately and implement manual lookup:

# Install: pip install timezonefinder
from timezonefinder import TimezoneFinder
from zoneinfo import ZoneInfo
from frequenz.client.microgrid import Location

tf = TimezoneFinder()
tz_name = tf.timezone_at(lat=52.52, lng=13.405)
timezone = ZoneInfo(tz_name) if tz_name else None
location = Location(latitude=52.52, longitude=13.405, timezone=timezone)

What's Changed

  • Clear release notes by @llucax in #157
  • Bump the minor group with 2 updates by @dependabot[bot] in #163
  • Bump the patch group with 5 updates by @dependabot[bot] in #162
  • Bump pytest-asyncio from 0.26.0 to 1.0.0 by @dependabot[bot] in #164
  • Remove timezonefinder dependency by @Copilot in #168
  • Bump mkdocs-material from 9.6.14 to 9.6.16 in the patch group by @dependabot[bot] in #169
  • Bump mypy from 1.16.1 to 1.17.1 in the minor group by @dependabot[bot] in #170
  • Bump types-markdown from 3.8.0.20250415 to 3.8.0.20250708 by @dependabot[bot] in #172
  • Bump pytest-asyncio from 1.0.0 to 1.1.0 by @dependabot[bot] in #174
  • Bump mkdocstrings[python] from 0.29.1 to 0.30.0 in the mkdocstrings group by @dependabot[bot] in #171
  • Bump async-solipsism from 0.7 to 0.8 by @dependabot[bot] in #175
  • Bump types-protobuf from 6.30.2.20250516 to 6.30.2.20250703 by @dependabot[bot] in #173
  • Bump the compatible group with 2 updates by @dependabot[bot] in #176

New Contributors

  • @Copilot made their first contribution in #168

Full Changelog: v0.9.0...v0.9.1

v0.9.0

11 Jun 07:13
v0.9.0
11e4c5e

Choose a tag to compare

Frequenz Microgrid API Client Release Notes

Summary

This is a small release to allow for easier interoperability between different APIs.

Upgrading

  • Some minimum dependency versions are bumped, so you might need to update your dependencies as well.

  • The IDs (MicrogridId, ComponentId, SensorId) are now imported from frequenz-client-common. Please add it to your dependencies if you haven't already, then you can replace your imports:

    • from frequenz.client.microgrid import MicrogridId -> from frequenz.client.common.microgrid import MicrogridId
    • from frequenz.client.microgrid import ComponentId -> from frequenz.client.common.microgrid.components import ComponentId
    • from frequenz.client.microgrid import SensorId -> from frequenz.client.common.microgrid.sensors import SensorId

What's Changed

Full Changelog: v0.8.0...v0.9.0

v0.8.0

27 May 10:28
v0.8.0
f2846aa

Choose a tag to compare

Frequenz Microgrid API Client Release Notes

Summary

This release introduces sensors support and adds official support for Python 3.12. It also includes some bug fixes.

Upgrading

  • Some minimum versions of dependencies have been bumped to support Python 3.12. You might also need to bump these dependencies in your project.
  • The ID classes (MicrogridId, ComponentId, etc.) were moved to the frequenz.client.microgrid.id module. They will be moved again, to frequenz-client-common in a near future.

New Features

  • The MicrogridApiClient can now list sensor retrieving their metadata (list_sensors()) and can stream sensor data (stream_sensor_data()).

Bug Fixes

  • When retrieving the microgrid metadata using metadata(), if the location was empty in the protobuf message, a wrong location with long=0, lat=0 was used. Now the location will be properly set to None in that case.
  • The client now does some missing cleanup (stopping background tasks) when disconnecting (and when used as a context manager).

What's Changed

Full Changelog: v0.7.0...v0.8.0

v0.7.0

24 Mar 13:56
v0.7.0
af4f0b5

Choose a tag to compare

Frequenz Microgrid API Client Release Notes

Upgrading

  • Now component and microgrid IDs are wrapped in new classes: ComponentId and MicrogridId respectively.

    These classes provide type safety and prevent accidental errors by:

    • Making it impossible to mix up microgrid and component IDs (equality comparisons between different ID types always return false).
    • Preventing accidental math operations on IDs.
    • Providing clear string representations for debugging (MID42, CID42).
    • Ensuring proper hash behavior in collections.

    To migrate you just need to wrap your int IDs with the appropriate class: 0 -> ComponentId(0) / MicrogridId(0).

What's Changed

Full Changelog: v0.6.1...v0.7.0

v0.6.1

20 Feb 14:12
v0.6.1
897f7fd

Choose a tag to compare

Frequenz Microgrid API Client Release Notes

Upgrading

  • Widen frequenz-client-base dependency to allow v0.9.0.

What's Changed

  • Clear release notes by @llucax in #102
  • Bump setuptools-scm[toml] from 7.1.0 to 8.1.0 by @dependabot in #105
  • Bump setuptools from 68.1.0 to 75.6.0 by @dependabot in #104
  • Bump the required group across 1 directory with 6 updates by @dependabot in #106
  • Bump types-markdown from 3.7.0.20240822 to 3.7.0.20241204 by @dependabot in #108
  • Bump the required group across 1 directory with 7 updates by @dependabot in #109
  • Bump black from 24.10.0 to 25.1.0 by @dependabot in #111
  • Bump the required group across 1 directory with 7 updates by @dependabot in #114
  • Revert "Enable autorefs plugin option to resolve closest references" by @llucax in #115
  • Bump isort from 5.13.2 to 6.0.0 by @dependabot in #112
  • Widen frequenz-client-base dependency to allow v0.9.0 by @shsms in #116

Full Changelog: v0.6.0...v0.6.1

v0.6.0

19 Nov 12:47
v0.6.0
985ad34

Choose a tag to compare

Frequenz Microgrid API Client Release Notes

Upgrading

  • ApiClient:

    • The class was renamed to MicrogridApiClient.
    • The api attribute was renamed to stub.
    • The constructor parameter channel_options was renamed to channels_defaults to match the name used in BaseApiClient.
    • The constructor now accepts a connect parameter, which is True by default. If set to False, the client will not connect to the server upon instantiation. You can connect later by calling the connect() method.
  • The frequenz-client-base dependency was bumped to v0.8.0.

New Features

  • The client now inherits from frequenz.client.base.BaseApiClient, so it provides a few new features, like disconnect()ing or using it as a context manager. Please refer to the BaseApiClient documentation for more information on these features.
  • The client now supports setting reactive power for components through the new set_reactive_power method.

What's Changed

  • Clear release notes by @llucax in #87
  • Inherit from BaseApiClient by @llucax in #88
  • Use call_stub_method() to call stub methods by @llucax in #89
  • Remove duplicated show_symbol_type_toc key in mkdocs.yml by @llucax in #90
  • Bump mkdocstrings dependencies by @llucax in #91
  • Bump the required group with 5 updates by @dependabot in #92
  • Bump the required group with 7 updates by @dependabot in #95
  • Bump types-protobuf from 4.21.0.7 to 5.28.3.20241030 by @dependabot in #97
  • Add the set_reactive_power method by @shsms in #99
  • Update the client-base dependency to v0.8.0 by @llucax in #100
  • Prepare for the v0.6.0 release by @llucax in #101

Full Changelog: v0.5.1...v0.6.0