Skip to content

Releases: frequenz-floss/frequenz-sdk-python

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

v0.16.4

30 Aug 14:07
d95944b
Compare
Choose a tag to compare

Release Notes

Bug Fixes

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

What's Changed

  • Remove broken CI steps that are not needed for v0.16.x by @shsms in #619

Full Changelog: v0.16.3...v0.16.4

v0.24.0

09 Aug 13:13
v0.24.0
1d45fc9
Compare
Choose a tag to compare

Frequenz Python SDK Release Notes

Summary

Now the microgrid API v0.15.x is being used. The SDK can only connect to microgrids using this version of the API. Inclusion and exclusion bounds in the new API are now handled by the power distributor and battery pool.

Upgrading

  • Upgrade to microgrid API v0.15.1. If you're using any of the lower level microgrid interfaces, you will need to upgrade your code.

  • The argument conf_file of the ConfigManagingActor constructor was renamed to config_path.

  • The BatteryPool.power_bounds method now streams inclusion/exclusion bounds. The bounds are now represented by Power objects and not floats.

New Features

  • The ConfigManagingActor constructor now can accept a pathlib.Path as config_path too (before it accepted only a str).

  • The PowerDistributingActor now considers exclusion bounds, when finding an optimal distribution for power between batteries.

What's Changed

  • Use Timer.periodic in the Resampler by @jh2007github in #520
  • Allow running release notes check in merge queues by @llucax in #566
  • Clear release notes by @llucax in #560
  • Update frequenz-api-microgrid to v0.15.1 by @shsms in #416
  • Improvements to the ConfigManagingActor by @llucax in #565
  • Bump brettcannon/check-for-changed-files from 294a99714e0d350b5083472a293d41bc91804e68 to 4170644959a21843b31f1181f2a1761d65ef4791 by @dependabot in #567
  • Bump types-protobuf from 4.23.0.2 to 4.23.0.3 by @dependabot in #568
  • Bump polars from 0.18.11 to 0.18.12 by @dependabot in #569
  • Stream exclusion bounds from the battery pool by @shsms in #537
  • Bump polars from 0.18.12 to 0.18.13 by @dependabot in #570
  • Add docs cross-linking to APIs by @llucax in #571
  • Support exclusion bounds in power distributor by @shsms in #562
  • Update release notes for the v0.24.0 release by @llucax in #573

Full Changelog: v0.23.0...v0.24.0

v0.23.0

03 Aug 08:20
v0.23.0
58ca166
Compare
Choose a tag to compare

Frequenz Python SDK Release Notes

Summary

This release ships many small improvements and bug fixes to Quantitys. It also depends on channels v0.16.0, so users must update the dependency too.

Upgrading

New Features

  • Quantities

    • Add support for the unary negative operator (negation of a quantity).
    • Add abs().
    • Add a isclose() method on quantities to compare them to other values of the same type. Because Quantity types are just wrappers around floats, direct comparison might not always be desirable.
    • Add zero() constructor (which returns a singleton) to easily get a zero value.
    • Add multiplication by Percentage types.
    • Add a new quantity class Frequency for frequency values.
    • Add a new quantity class Temperature for temperature values.
  • FormulaEngine arithmetics now supports scalar multiplication with floats and addition with Quantitys.

  • Add a new temperature method for streaming average temperature values for the battery pool.

Bug Fixes

  • Fix formatting issue for Quantity objects with zero values.
  • Fix formatting issue for Quantity when the base value fulfills math.isinf() or math.isnan().
  • Fix clamping to 100% for the battery pool SoC scaling calculation.
  • Fix indexing for empty MovingWindows (now it properly raises an IndexError).

What's Changed

New Contributors

  • @jh2007github made their first contribution in #484

Full Changelog: v0.22.0...v0.23.0

v0.22.1

11 Jul 15:52
v0.22.1
1b77adc
Compare
Choose a tag to compare

Release Notes

Bug Fixes

  • Fix formatting issue for Quantity objects with zero values.

What's Changed

  • Fix formatting bug for zero values by @shsms in #503

Full Changelog: v0.22.0...v0.22.1

v0.22.0

04 Jul 12:17
v0.22.0
1b7053e
Compare
Choose a tag to compare

Release Notes

Summary

New Quantity types! These types can have units (power, current, voltage, etc.) and are type- and unit-safe in the sense that users can't accidentally sum a power with a voltage, or a power in kW with a power in W.

Upgrading

  • Sample objects no longer hold floats, but rather Quantity or one of its subclasses, like Power, Current, Energy, etc. based on the type of values being streamed.

    sample: Sample[Power] = await battery_pool.power.new_receiver().receive()
    power: float = sample.value.as_watts()
  • BatteryPool.soc now streams values of type Sample[Quantity], and BatteryPool.capacity now streams values of type Sample[Energy].

    battery_pool = microgrid.battery_pool()
    soc_sample: Sample[Quantity] = await battery_pool.soc.new_receiver().receive()
    soc: float = soc_sample.value.base_value
    
    capacity_sample: Sample[Energy] = await battery_pool.capacity.new_receiver().receive()
    capacity: float = soc_sample.value.as_watt_hours()
  • MicrogridApiClient.set_power no longer returns a protobuf.Empty result, but a None. This won't affect you unless you are using the low level APIs of the SDK.

New Features

  • The logical meter has a new method that returns producer power, that is the sum of all energy producers.

  • Quantity types (Power, Current, Energy, Voltage) for providing type- and unit-safety when dealing with physical quantities.

Bug Fixes

  • Two bugs in the ring buffer which is used by the MovingWindow class were fixed:

    • len(buffer) was not considering potentially existing gaps (areas without elements) in the buffer.
    • A off-by-one error in the gap calculation logic was fixed that recorded a gap when there was none if an element with a future timestamp was added that would create a gap of exactly 1.
  • A formula engine lifetime issue, when creating higher order formula receivers without holding on to a reference to the engine, was fixed.

What's Changed

New Contributors

Full Changelog: v0.21.1...v0.22.0