Skip to content

Commit 3c11c7f

Browse files
committed
Add steam boiler pool
Signed-off-by: Simon Völcker <simon.voelcker@frequenz.com>
1 parent 770d768 commit 3c11c7f

5 files changed

Lines changed: 141 additions & 1 deletion

File tree

‎pyproject.toml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ dependencies = [
2929
# Make sure to update the mkdocs.yml file when
3030
# changing the version
3131
# (plugins.mkdocstrings.handlers.python.import)
32-
"frequenz-client-microgrid >= 0.18.1, < 0.19.0",
32+
"frequenz-client-microgrid >= 0.18.2, < 0.19.0",
3333
"frequenz-microgrid-component-graph >= 0.3.4, < 0.4",
3434
"frequenz-client-common >= 0.3.6, < 0.4.0",
3535
"frequenz-channels >= 1.6.1, < 2.0.0",
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# License: MIT
2+
# Copyright © 2026 Frequenz Energy-as-a-Service GmbH
3+
4+
"""Interactions with steam boilers."""
5+
6+
from ._result_types import SteamBoilerPoolReport
7+
from ._steam_boiler_pool import SteamBoilerPool, SteamBoilerPoolError
8+
9+
__all__ = [
10+
"SteamBoilerPool",
11+
"SteamBoilerPoolError",
12+
"SteamBoilerPoolReport",
13+
]
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# License: MIT
2+
# Copyright © 2026 Frequenz Energy-as-a-Service GmbH
3+
4+
"""Types for exposing steam boiler pool reports."""
5+
6+
import typing
7+
8+
from frequenz.quantities import Power
9+
10+
from .. import Bounds
11+
from ..component_pool._component_pool_report import ComponentPoolReport
12+
13+
14+
class SteamBoilerPoolReport(ComponentPoolReport, typing.Protocol):
15+
"""A status report for a steam boiler pool."""
16+
17+
@property
18+
def target_power(self) -> Power | None:
19+
"""The currently set power for the steam boilers."""
20+
21+
@property
22+
def bounds(self) -> Bounds[Power] | None:
23+
"""The usable bounds for the steam boilers.
24+
25+
These bounds are adjusted to any restrictions placed by actors with higher
26+
priorities.
27+
"""
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# License: MIT
2+
# Copyright © 2026 Frequenz Energy-as-a-Service GmbH
3+
4+
"""Interactions with pools of steam boilers."""
5+
6+
from frequenz.quantities import Power
7+
from typing_extensions import override
8+
9+
from ...microgrid import connection_manager
10+
from ..component_pool import ComponentPool
11+
from ..formulas import Formula
12+
from ._result_types import SteamBoilerPoolReport
13+
from ._steam_boiler_pool_reference_store import SteamBoilerPoolReferenceStore
14+
15+
16+
class SteamBoilerPoolError(Exception):
17+
"""An error that occurred in any of the SteamBoilerPool methods."""
18+
19+
20+
class SteamBoilerPool(
21+
ComponentPool[SteamBoilerPoolReferenceStore, SteamBoilerPoolReport]
22+
):
23+
"""An interface for interaction with pools of steam boilers."""
24+
25+
@property
26+
@override
27+
def power(self) -> Formula[Power]:
28+
"""Fetch the total power for the steam boilers in the pool.
29+
30+
This formula produces values that are in the Passive Sign Convention (PSC).
31+
32+
If a formula to calculate steam boiler power is not already running, it
33+
will be started.
34+
35+
A receiver from the formula can be created using the `new_receiver`
36+
method.
37+
38+
Returns:
39+
A Formula that will calculate and stream the total power of all steam boilers.
40+
"""
41+
return self._pool_ref_store.formula_pool.from_power_formula(
42+
"steam_boiler_power",
43+
# TODO component graph update needed, still under review
44+
connection_manager.get().component_graph.steam_boiler_formula(
45+
self._pool_ref_store.component_ids
46+
),
47+
)
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
# License: MIT
2+
# Copyright © 2026 Frequenz Energy-as-a-Service GmbH
3+
4+
"""Manages shared state/tasks for a set of steam boilers."""
5+
6+
import uuid
7+
from typing import Type
8+
9+
from frequenz.client.microgrid.component import (
10+
Component,
11+
SteamBoiler, # TODO client 0.19.1 needed, under review
12+
)
13+
from typing_extensions import override
14+
15+
from ..component_pool._component_pool_reference_store import ComponentPoolReferenceStore
16+
17+
18+
class SteamBoilerPoolReferenceStore(ComponentPoolReferenceStore):
19+
"""A class for maintaining the shared state/tasks for a set of pools of steam boilers.
20+
21+
This includes ownership of
22+
- the formula pool and metric calculators.
23+
- the tasks for calculating system bounds for the steam boilers.
24+
25+
These are independent of the priority of the actors and can be shared between
26+
multiple users of the same set of steam boilers.
27+
28+
They are exposed through the SteamBoilerPool class.
29+
"""
30+
31+
@staticmethod
32+
def get_component_class() -> Type[Component]:
33+
"""Class of the component type."""
34+
return SteamBoiler
35+
36+
@staticmethod
37+
def get_pool_type_name() -> str:
38+
"""Name of the pool type, for display purposes."""
39+
return "SteamBoilerPool"
40+
41+
@staticmethod
42+
def get_component_type_name_plural() -> str:
43+
"""Name of the component type, for display purposes."""
44+
return "steam boilers"
45+
46+
@override
47+
def get_namespace(self) -> str:
48+
"""Namespace to use with the data pipeline."""
49+
return f"steam-boiler-pool-{uuid.uuid4()}"
50+
51+
@override
52+
def create_bounds_tracker(self) -> None:
53+
"""Create the bounds tracker for the pool."""

0 commit comments

Comments
 (0)