Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions RELEASE_NOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@

## New Features

* Add CLI tool to print formulas from assets API component graph.

<!-- Here goes the main new features and examples or instructions on how to use them -->

## Bug Fixes
Expand Down
9 changes: 5 additions & 4 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ description = "High-level interface to grid pools for the Frequenz platform."
readme = "README.md"
license = { text = "MIT" }
keywords = ["frequenz", "python", "lib", "library", "gridpool"]
# TODO(cookiecutter): Remove and add more classifiers if appropriate
classifiers = [
"Development Status :: 3 - Alpha",
"Intended Audience :: Developers",
Expand All @@ -26,20 +25,22 @@ classifiers = [
"Typing :: Typed",
]
requires-python = ">= 3.11, < 4"
# TODO(cookiecutter): Remove and add more dependencies if appropriate
dependencies = [
"marshmallow-dataclass>=8.7.1,<9",
"marshmallow-dataclass >= 8.7.1, < 9",
"asyncclick >= 8.3.0.4, < 9",
"typing-extensions >= 4.14.1, < 5",
"frequenz-microgrid-component-graph >= 0.2.0, < 0.3",
"frequenz-client-assets >= 0.2.0, < 0.3",
]
dynamic = ["version"]

[project.scripts]
gridpool-cli = "frequenz.gridpool.cli.__main__:main"

[[project.authors]]
name = "Frequenz Energy-as-a-Service GmbH"
email = "floss@frequenz.com"

# TODO(cookiecutter): Remove and add more optional dependencies if appropriate
[project.optional-dependencies]
dev-flake8 = [
"flake8 == 7.3.0",
Expand Down
1 change: 1 addition & 0 deletions src/frequenz/gridpool/cli/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"""Package for CLI tool for gridpool functionality."""
72 changes: 72 additions & 0 deletions src/frequenz/gridpool/cli/__main__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# License: MIT
# Copyright © 2025 Frequenz Energy-as-a-Service GmbH

"""CLI tool for gridpool functionality."""

import os

import asyncclick as click
from frequenz.client.assets import AssetsApiClient
from frequenz.client.common.microgrid import MicrogridId

from frequenz.gridpool import ComponentGraphGenerator


@click.group()
async def cli() -> None:
"""CLI tool for gridpool functionality."""


@cli.command()
@click.argument("microgrid_id", type=int)
@click.option(
"--prefix",
type=str,
default="{component}",
help="Prefix format for the output (Supports {microgrid_id} and {component} placeholders).",
)
async def print_formulas(
microgrid_id: int,
prefix: str,
) -> None:
"""Fetch and print component graph formulas for a microgrid."""
url = os.environ.get("ASSETS_API_URL")
key = os.environ.get("ASSETS_API_AUTH_KEY")
secret = os.environ.get("ASSETS_API_SIGN_SECRET")
if not url or not key or not secret:
raise click.ClickException(
"ASSETS_API_URL, ASSETS_API_AUTH_KEY, ASSETS_API_SIGN_SECRET must be set."
)

async with AssetsApiClient(
url,
auth_key=key,
sign_secret=secret,
) as client:
cgg = ComponentGraphGenerator(client)

graph = await cgg.get_component_graph(MicrogridId(microgrid_id))
power_formulas = {
"consumption": graph.consumer_formula(),
"generation": graph.producer_formula(),
"grid": graph.grid_formula(),
"pv": graph.pv_formula(None),
"battery": graph.battery_formula(None),
"chp": graph.chp_formula(None),
"ev": graph.ev_charger_formula(None),
}

for component, formula in power_formulas.items():
print(
prefix.format(component=component, microgrid_id=microgrid_id)
+ f' = "{formula}"'
)


def main() -> None:
"""Run the CLI tool."""
cli(_anyio_backend="asyncio")


if __name__ == "__main__":
main()