Skip to content

Releases: frequenz-floss/frequenz-sdk-python

v1.0.0-rc601

02 May 12:58
v1.0.0-rc601
9c54f8d
Compare
Choose a tag to compare

Frequenz Python SDK Release Notes

In this release we have changed the versioning scheme for pre-releases. rc601 means rc6.1, which we can't use due to limitations on the Python version specification. From now on rc versions will have 3 digits, so next rc will be rc700, and then rc800 etc, so we have some room to make patch releases in case it is necessary (which will be named rc701, rc702, etc.).

Bug Fixes

  • Fix getting reactive power from meters, inverters and EV chargers.

What's Changed

Read more

v1.0.0-rc6

12 Apr 14:25
v1.0.0-rc6
57337df
Compare
Choose a tag to compare
v1.0.0-rc6 Pre-release
Pre-release

Frequenz Python SDK Release Notes

Summary

The most notable features for this release is the addition of the PVPool (exposed via microgrid.pv_pool()), which can be used to manage PV arrays as a single entity and the EVChargerPool (microgrid.ev_charger_pool()) learning to manage power for the whole pool (before it could only be used to control chargers individually).

Another notable change is the microgrid API client being moved to its own repository.

Upgrading

  • The SDK is now using the microgrid API client from frequenz-client-microgrid. You should update your code if you are using the microgrid API client directly.

  • The minimum required frequenz-channels version is now v1.0.0-rc1.

  • The set of battery IDs managed by a battery pool are now available through BatteryPool.component_ids, and no longer through BatteryPool.battery_ids. This is done to have a consistent interface with other *Pools.

  • The maxsize parameter in calls to BatteryPool.{soc/capacity/temperature}.new_receiver() methods have now been renamed to limit, to be consistent with the channels repository.

  • Support for per-component interaction in EVChargerPool has been removed. Please use the new propose_power() method to manage power for the whole pool. If you still need to manage power of chargers individually, you can create one pool per charger.

  • PV power is now available from microgrid.pv_pool().power, and no longer from microgrid.logical_meter().pv_power.

New Features

  • EVChargerPool/microgrid.ev_charger_pool(): New propose_power and power_status methods have been added, similar to the BatteryPool. These method interface with the PowerManager and PowerDistributor, which currently uses a first-come-first-serve algorithm to distribute power to EVs.

  • A PV pool (PVPool/microgrid.pv_pool()) was added, with propose_power, power_status and power methods similar to Battery and EV pools.

  • The microgrid API client now exposes the reactive power for inverters, meters and EV chargers.

Enhancements

  • Warning messages are logged when multiple instances of *Pools are created for the same set of batteries, with the same priority values.

  • A warning message will now be logged if no relevant samples are found in a component for resampling.

Bug Fixes

  • A bug was fixed where the grid fuse was not created properly and would end up with a max_current with type float instead of Current.

  • BatteryPool.propose_discharge now converts power values to the passive-sign convention. Earlier it was not doing this and that was causing it to charge instead of discharge.

  • Fix a bug that was causing the power managing actor to crash and restart when cleaning up old proposals.

What's Changed

Read more

v1.0.0-rc5

26 Feb 14:42
v1.0.0-rc5
9f9520c
Compare
Choose a tag to compare
v1.0.0-rc5 Pre-release
Pre-release

Frequenz Python SDK Release Notes

Summary

This is a minor non-breaking release that adds new features and fixes a few bug.

New Features

  • Allow multiplying and dividing any Quantity by a float. This just scales the Quantity value.
  • Allow dividing any Quantity by another quaintity of the same type. This just returns a ration between both quantities.
  • The battery pool power method now supports scenarios where one or more inverters can have multiple batteries connected to it and one or more batteries can have multiple inverters connected to it.

Bug Fixes

  • Fix grid current formula generator to add the operator + to the engine only when the component category is handled.
  • Fix bug where sometimes the base_value of a Quantity could be of a different type than float.

What's Changed

  • Clear release notes by @llucax in #871
  • Fetch and stream 3-phase power by @daniel-zullo-frequenz in #847
  • Remove remaining traces of darglint by @llucax in #873
  • Make sure base_value is always float by @llucax in #874
  • Remove the last reference to darglint by @llucax in #877
  • Mock resampler: Improve variable names by @llucax in #879
  • Allow multiplying Quantity by float by @llucax in #875
  • Remove unnecessary send adapter by @llucax in #878
  • Bump actions/{up,down}load-artifact from 3 to 4 by @dependabot in #833
  • Allow all quantities division by float | Self by @llucax in #876
  • Cleanup and modularization of Power Manager, Power Distributor and DataPipeline by @shsms in #881
  • More updates for n:m support - battery pool's power formula by @Marenz in #730
  • Prepare release notes for 1.0.0-rc5 by @llucax in #884

Full Changelog: v1.0.0-rc4...v1.0.0-rc5

v1.0.0-rc4

02 Feb 13:20
v1.0.0-rc4
3ef0981
Compare
Choose a tag to compare
v1.0.0-rc4 Pre-release
Pre-release

Frequenz Python SDK Release Notes

Summary

This release represents 3 months of work so it includes a lot of changes. Most of them are (breaking) API changes, in the hopes to make a more consistent and easier to use SDK 1.0. There are also quite a few bug fixes and a couple of new features.

Upgrading

  • The BatteryPool.power_status method now streams objects of type BatteryPoolReport, replacing the previous Report objects.

  • Channels has been upgraded to version 1.0.0b2, for information on how to upgrade please read Channels release notes.

  • In BatteryPoolReport.distribution_result,

    • the following fields have been renamed:
      • Result.succeeded_batteriesResult.succeeded_components
      • Result.failed_batteriesResult.failed_components
      • Request.batteriesRequest.component_ids
    • and the following fields are now type-hinted as collections.abc.Set, to clearly indicate that they are read-only:
      • Result.succeeded_components
      • Result.failed_components
  • The Fuse class has been moved to the frequenz.sdk.timeseries module.

  • microgrid.grid()

    • A Grid object is always instantiated now, even if the microgrid is not connected to the grid (islanded microgrids).

    • The rated current of the grid fuse is set to Current.zero() in case of islanded microgrids.

    • The grid fuse is set to None when the grid connection component metadata lacks information about the fuse.

    • Grid power and current metrics were moved from microgrid.logical_meter() to microgrid.grid().

      Previously,

      logical_meter = microgrid.logical_meter()
      grid_power_recv = logical_meter.grid_power.new_receiver()
      grid_current_recv = logical_meter.grid_current.new_receiver()

      Now,

      grid = microgrid.grid()
      grid_power_recv = grid.power.new_receiver()
      grid_current_recv = grid.current.new_receiver()
  • Consumer and producer power formulas were moved from microgrid.logical_meter() to microgrid.consumer() and microgrid.producer(), respectively.

    Previously,

    logical_meter = microgrid.logical_meter()
    consumer_power_recv = logical_meter.consumer_power.new_receiver()
    producer_power_recv = logical_meter.producer_power.new_receiver()

    Now,

    consumer_power_recv = microgrid.consumer().power.new_receiver()
    producer_power_recv = microgrid.producer().power.new_receiver()
  • The ComponentGraph.components() parameters component_id and component_category were renamed to component_ids and component_categories, respectively.

  • The GridFrequency.component property was renamed to GridFrequency.source

  • The microgrid.frequency() method no longer supports passing the component parameter. Instead the best component is automatically selected.

  • The actor.ChannelRegistry was rewritten to be type-aware and just a container of channels. You now need to provide the type of message that will be contained by the channel and use the get_or_create() method to get a channel and the stop_and_remove() method to stop and remove a channel. Once you get a channel you can create new senders and receivers, or set channel options, as usual. Please read the docs for a full description, but in general this:

    r = registry.new_receiver(name)
    s = registry.new_sender(name)

    Should be replaced by:

    r = registry.get_or_create(T, name).new_receiver()
    s = registry.get_or_create(T, name).new_sender()
  • The ReceiverFetcher interface was slightly changed to make maxsize a keyword-only argument. This is to make it compatible with the Broadcast channel, so it can be considered a ReceiverFetcher.

New Features

  • A new method microgrid.voltage() was added to allow easy access to the phase-to-neutral 3-phase voltage of the microgrid.

  • The actor.ChannelRegistry is now type-aware.

  • A new class method Quantity.from_string() has been added to allow the creation of Quantity objects from strings.

Bug Fixes

  • 0W power requests are now not adjusted to exclusion bounds by the PowerManager and PowerDistributor, and are sent over to the microgrid API directly.

  • microgrid.frequency() / GridFrequency:

    • Fix sent samples to use Frequency objects instead of raw Quantity.
    • Handle None values in the received samples properly.
    • Convert nan values in the received samples to None.
  • The resampler now properly handles sending zero values.

    A bug made the resampler interpret zero values as None when generating new samples, so if the result of the resampling is zero, the resampler would just produce None values.

  • The PowerManager no longer holds on to proposals from dead actors forever. If an actor hasn't sent a new proposal in 60 seconds, the available proposal from that actor is dropped.

  • Fix Quantity.__format__() sometimes skipping the number for very small values.

  • Not strictly a bug fix, but the microgrid API version was bumped to v0.15.3, which indirectly bumps the common API dependency to v0.5.x, so the SDK can be compatible with other APIs using a newer version of the common API.

    Downstream projects that require a frequenz-api-common v0.5.x and want to ensure proper dependency resolution should update their minimum SDK version to this release.

What's Changed

Read more

v0.25.2

11 Dec 13:51
v0.25.2
7716937
Compare
Choose a tag to compare

Frequenz Python SDK Release Notes

Bug Fixes

  • The resampler now properly handles sending zero values.

    A bug made the resampler interpret zero values as None when generating new samples, so if the result of the resampling is zero, the resampler would just produce None values.

What's Changed

Full Changelog: v0.25.1...v0.25.2

v1.0.0-rc3

08 Nov 11:35
v1.0.0-rc3
504b86f
Compare
Choose a tag to compare
v1.0.0-rc3 Pre-release
Pre-release

Frequenz Python SDK Release Notes

Summary

The microgrid package now exposes grid connections uniformly and introduces formula operators for consumption and production, replacing the logical_meter.*_{production,consumption}() formulas. The actor package restarts crashed actors with a delay, and the ConnectionManager exposes the microgrid_id and location details.

There are also a few bug fixes, documentation improvements and other minor breaking changes.

Upgrading

  • actor package

    • Actors are now restarted after a small delay when they crash to avoid a busy loop and spamming the logs if the actor keeps failing to start.

    • The include_broken_batteries argument was removed from the PowerDistributingActor's Request. This option is no longer supported.

  • microgrid package

    • grid: The grid connection is now exposed as microgrid.grid(). This is more consistent with other objects exposed in the microgrid module, such as microgrid.battery_pool() and microgrid.logical_meter().

    • battery_pool(): The include_broken_batteries argument was removed from the propose_*() methods (it was also removed from the underlying type, timeseries.BatteryPool). This option is no longer supported.

    • ComponentGraph: The component graph is now exposed as microgrid.component_graph.ComponentGraph.

    • logical_meter(): The *_consumption() and *_production() methods were removed. You should use the new consumption and production formula operators instead.

      For example:

      # Old:
      pv_consumption = logical_meter.pv_consumption_power()
      production = (logical_meter.pv_production_power() + logical_meter.chp_production_power()).build()
      # New:
      pv_consumption = logical_meter.pv_power().consumption().build()
      production = (logical_meter.pv_power().production() + logical_meter.chp_power().production()).build()

New Features

  • The configuration flag resend_latest can now be changed for channels owned by the ChannelRegistry.

  • New formula operators for calculating consumption() and production() were added.

  • The ConnectionManager now fetches microgrid metadata when connecting to the microgrid and exposes microgrid_id and location properties of the connected microgrid.

    Users can access this information using microgrid.connection_manager.get().microgrid_id and microgrid.connection_manager.get().location.

  • The documentation has been improved to:

    • Display signatures with types.
    • Show inherited members.
    • Publish documentation for pre-releases.
    • Present the full tag name as the documentation version.
    • Ensure all development branches have their documentation published (the next version has been removed).
    • Fix the order of the documentation versions.

Bug Fixes

  • Fixed incorrect grid current calculations in locations where the calculations depended on current measurements from an inverter.

  • Corrected the power failure report to exclude any failed power calculations from the successful ones.

What's Changed

New Contributors

Full Changelog: v1.0.0-rc2...v1.0.0-rc3

v1.0.0-rc2

13 Oct 14:08
v1.0.0-rc2
e04ee95
Compare
Choose a tag to compare
v1.0.0-rc2 Pre-release
Pre-release

Frequenz Python SDK Release Notes

Summary

This version ships an experimental version of the Power Manager and includes user documentation.

Upgrading

  • microgrid.battery_pool() method now accepts a priority value.

  • BatteryPool's control methods

    • Original methods {set_power/charge/discharge} are now replaced by propose_{power/charge/discharge}
    • The propose_* methods send power proposals to the PowerManagingActor, where it can be overridden by proposals from other actors.
    • They no longer have the adjust_power flag, because the PowerManagingActor will always adjust power to fit within the available bounds.
  • BatteryPool's reporting methods

    • power_bounds is replaced by power_status
    • The power_status method streams objects containing:
      • bounds adjusted to the actor's priorities
      • the latest target power for the set of batteries
      • the results from the power distributor for the last request

New Features

  • New and improved documentation.

    • A new User Guide section was added, with:

      • A glossary.
      • An introduction to actors.
    • A new Tutorials section was added, with:

      • A getting started tutorial.
  • In OrderedRingBuffer:

    • Rename datetime_to_index to to_internal_index to avoid confusion between the internal index and the external index.
    • Add index_to_datetime method to convert external index to corresponding datetime.
    • Remove __setitem__ method to enforce usage of dedicated update method only.
  • In OrderedRingBuffer and MovingWindow:

    • Support for integer indices is added.
    • Add count_covered method to count the number of elements covered by the used time range.
    • Add fill_value option to window method to impute missing values. By default missing values are imputed with NaN.
  • Add at method to MovingWindow to access a single element and use it in __getitem__ magic to fully support single element access.

  • The PowerDistributingActor now supports n:m relations between inverters and batteries.

    This means that one or more inverters can be connected to one or more batteries.

  • A PowerManagingActor implementation

Bug Fixes

  • Fix rendering of diagrams in the documentation.
  • The __getitem__ magic of the MovingWindow is fixed to support the same functionality that the window method provides.
  • Fixes incorrect implementation of single element access in __getitem__ magic of MovingWindow.

What's Changed

Full Changelog: v1.0.0-rc1...v1.0.0-rc2

v1.0.0-rc1

14 Sep 14:43
v1.0.0-rc1
892403e
Compare
Choose a tag to compare
v1.0.0-rc1 Pre-release
Pre-release

Frequenz Python SDK Release Notes

Summary

The most notable changes are the addition of microgrid.grid and microgrid.frequency(), as the many improvements to the MovingWindow.

Upgrading

  • The battery pool metric methods no longer return None when no batteries are available. Instead, the value of the Sample or PowerMetric is set to None.

  • The power distribution Result is now a union of all different types of results rather than a base class. This means we can now also use match to check for result types instead of only using isinstance(). The following example shows how Result can be used for matching power distribution results:

    from typing import assert_never
    result: Result = some_operation()
    match result:
        case Success() as success:
            print(f"Power request was successful: {success}")
        case PartialFailure() as partial_failure:
            print(f"Power request was partially successful: {partial_failure}")
        case OutOfBounds() as out_of_bounds:
            print(f"Power request was out of bounds: {out_of_bounds}")
        case Error() as error:
            print(f"Power request failed: {error}")
        case _ as unreachable:
            assert_never(unreachable)
  • Averager was removed from FormulaEngine.

New Features

  • Calling microgrid.initialize() now also initializes the microgrid's grid connection point as a singleton object of a newly added type Grid. This object can be obtained by calling microgrid.grid.get(). This object exposes the max current that can course through the grid connection point, which is useful for the power distribution algorithm. The max current is provided by the Microgrid API, and can be obtained by calling microgrid.grid.get().fuse.max_current.

    Note that a microgrid is allowed to have zero or one grid connection point. Microgrids configured as islands will have zero grid connection points, and microgrids configured as grid-connected will have one grid connection point.

  • A new method microgrid.frequeny() was added to allow easy access to the current frequency of the grid.

  • A new class Fuse has been added to represent fuses. This class has a member variable max_current which represents the maximum current that can course through the fuse. If the current flowing through a fuse is greater than this limit, then the fuse will break the circuit.

  • MovingWindow and OrderedRingBuffer:

    • NaN values are treated as missing when gaps are determined in the OrderedRingBuffer.
    • Provide access to capacity (maximum number of elements) in MovingWindow.
    • Methods to retrieve oldest and newest timestamp of valid samples are added to both.
    • MovingWindow exposes underlying buffers window method.
    • len(window) and len(buffer) should be replaced with window.count_valid() and buffer.count_valid(), respectively.
    • OrderedRingBuffer.window:
      • By default returns a copy.
      • Can also return a view if the window contains None values and if force_copy is set to True.
  • Now when printing FormulaEngine for debugging purposes the the formula will be shown in infix notation, which should be easier to read.

  • The CI now runs cross-arch tests on arm64 architectures.

  • The min and max functions in the FormulaEngine are now public. Note that the same functions have been public in the builder.

Bug Fixes

  • OrderedRingBuffer.window:
    • Fixed force_copy option for specific case.
    • Removed buggy enforcement of copies when None values in queried window.
    • Fixed behavior for start equals end case.

What's Changed

New Contributors

Full Changelog: v0.25.1...v1.0.0-rc1

v0.25.1

08 Sep 11:51
v0.25.1
58db6bc
Compare
Choose a tag to compare

Frequenz Python SDK Release Notes

Bug Fixes

  • Fix the API Reference link in the documentation website navigation bar.

  • Fix the consumer power formula

What's Changed

Full Changelog: v0.25.0...v0.25.1

v0.25.0

30 Aug 10:38
v0.25.0
5d1f7d7
Compare
Choose a tag to compare

Frequenz Python SDK Release Notes

Summary

This release replaces the @actor decorator with a new Actor class.

Upgrading

  • The frequenz.sdk.power package contained the power distribution algorithm, which is for internal use in the sdk, and is no longer part of the public API.

  • PowerDistributingActor's result type OutOfBound has been renamed to OutOfBounds, and its member variable bound has been renamed to bounds.

  • The @actor decorator was replaced by the new Actor class. The main differences between the new class and the old decorator are:

    • It doesn't start automatically, start() needs to be called to start an actor (using the frequenz.sdk.actor.run() function is recommended).
    • The method to implement the main logic was renamed from run() to _run(), as it is not intended to be run externally.
    • Actors can have an optional name (useful for debugging/logging purposes).
    • The actor will only be restarted if an unhandled Exception is raised by _run(). It will not be restarted if the _run() method finishes normally. If an unhandled BaseException is raised instead, it will be re-raised. For normal cancellation the _run() method should handle asyncio.CancelledError if the cancellation shouldn't be propagated (this is the same as with the decorator).
    • The _stop() method is public (stop()) and will cancel() and await for the task to finish, catching the asyncio.CancelledError.
    • The join() method is renamed to wait(), but they can also be awaited directly ( await actor).
    • For deterministic cleanup, actors can now be used as async context managers.

    Most actors can be migrated following these steps:

    1. Remove the decorator
    2. Add Actor as a base class
    3. Rename run() to _run()
    4. Forward the name argument (optional but recommended)

    For example, this old actor:

    from frequenz.sdk.actor import actor
    
    @actor
    class TheActor:
        def __init__(self, actor_args) -> None:
            # init code
    
        def run(self) -> None:
            # run code

    Can be migrated as:

    import asyncio
    from frequenz.sdk.actor import Actor
    
    class TheActor(Actor):
        def __init__(self, actor_args,
            *,
            name: str | None = None,
        ) -> None:
            super().__init__(name=name)
            # init code
    
        def _run(self) -> None:
            # run code

    Then you can instantiate all your actors first and then run them using:

    from frequenz.sdk.actor import run
    # Init code
    actor = TheActor()
    other_actor = OtherActor()
    # more setup
    await run(actor, other_actor)  # Start and await for all the actors
  • The MovingWindow is now a BackgroundService, so it needs to be started manually with window.start(). It is recommended to use it as an async context manager if possible though:

    async with MovingWindow(...) as window:
        # The moving windows is started here
        use(window)
    # The moving window is stopped here
  • The base actors (ConfigManagingActor, ComponentMetricsResamplingActor, DataSourcingActor, PowerDistributingActor) now inherit from the new Actor class, if you are using them directly, you need to start them manually with actor.start() and you might need to do some other adjustments.

  • The BatteryPool.power_distribution_results method has been enhanced to provide power distribution results in the form of Power objects, replacing the previous use of float values.

  • In the Request class:

    • The attribute request_timeout_sec has been updated and is now named request_timeout and it is represented by a timedelta object rather than a float.
    • The attribute power is now presented as a Power object, as opposed to a float.
  • Within the EVChargerPool.set_bounds method, the parameter max_amps has been redefined as max_current, and it is now represented using a Current object instead of a float.

  • The argument nones_are_zeros in FormulaEngine and related classes and methods is now a keyword-only argument.

New Features

  • Added DFS to the component graph

  • BackgroundService: This new abstract base class can be used to write other classes that runs one or more tasks in the background. It provides a consistent API to start and stop these services and also takes care of the handling of the background tasks. It can also work as an async context manager, giving the service a deterministic lifetime and guaranteed cleanup.

    All classes spawning tasks that are expected to run for an indeterminate amount of time are likely good candidates to use this as a base class.

  • Actor: This new class inherits from BackgroundService and it replaces the @actor decorator.

  • Newly added min and max functions for Formulas. They can be used as follows:

    formula1.min(formula2)

Bug Fixes

  • Fixes a bug in the ring buffer updating the end timestamp of gaps when they are outdated.

  • Properly handles PV configurations with no or only some meters before the PV component.

    So far we only had configurations like this: Meter -> Inverter -> PV. However the scenario with Inverter -> PV is also possible and now handled correctly.

  • Fix consumer_power() not working certain configurations.

    In microgrids without consumers and no main meter, the formula would never return any values.

  • Fix pv_power not working in setups with 2 grid meters by using a new reliable function to search for components in the components graph

  • Fix consumer_power and producer_power similar to pv_power

  • Zero value requests received by the PowerDistributingActor will now always be accepted, even when there are non-zero exclusion bounds.

  • Hold on to a reference to all streaming tasks in the microgrid API client, so they don't get garbage collected.

What's Changed

New Contributors

Full Changelog: https://github.com/frequenz...

Read more