Skip to content

Commit 8697782

Browse files
committed
Add code example for reporting client usage
Signed-off-by: cwasicki <[email protected]>
1 parent 14ef9ff commit 8697782

File tree

2 files changed

+145
-0
lines changed

2 files changed

+145
-0
lines changed

examples/client.py

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
# License: MIT
2+
# Copyright © 2024 Frequenz Energy-as-a-Service GmbH
3+
4+
"""Examples usage of reporting API."""
5+
6+
import argparse
7+
import asyncio
8+
from datetime import datetime
9+
from pprint import pprint
10+
from typing import AsyncGenerator
11+
12+
import pandas as pd
13+
from frequenz.client.common.metric import Metric
14+
15+
from frequenz.client.reporting import ReportingClient
16+
17+
# Experimental import
18+
from frequenz.client.reporting._client import MetricSample
19+
20+
21+
# pylint: disable=too-many-locals
22+
async def main(microgrid_id: int, component_id: int) -> None:
23+
"""Test the ReportingClient.
24+
25+
Args:
26+
microgrid_id: int
27+
component_id: int
28+
"""
29+
service_address = "localhost:50051"
30+
client = ReportingClient(service_address)
31+
32+
microgrid_components = [(microgrid_id, [component_id])]
33+
metrics = [
34+
Metric.DC_POWER,
35+
Metric.DC_CURRENT,
36+
]
37+
38+
start_dt = datetime.fromisoformat("2023-11-21T12:00:00.00+00:00")
39+
end_dt = datetime.fromisoformat("2023-11-21T12:01:00.00+00:00")
40+
41+
page_size = 10
42+
43+
print("########################################################")
44+
print("Iterate over single metric generator")
45+
46+
async for sample in client.iterate_single_metric(
47+
microgrid_id=microgrid_id,
48+
component_id=component_id,
49+
metric=metrics[0],
50+
start_dt=start_dt,
51+
end_dt=end_dt,
52+
page_size=page_size,
53+
):
54+
print("Received:", sample)
55+
56+
###########################################################################
57+
#
58+
# The following code is experimental and demonstrates potential future
59+
# usage of the ReportingClient.
60+
#
61+
###########################################################################
62+
63+
async def components_data_iter() -> AsyncGenerator[MetricSample, None]:
64+
"""Iterate over components data.
65+
66+
Yields:
67+
Single metric sample
68+
"""
69+
# pylint: disable=protected-access
70+
async for page in client._iterate_components_data_pages(
71+
microgrid_components=microgrid_components,
72+
metrics=metrics,
73+
start_dt=start_dt,
74+
end_dt=end_dt,
75+
page_size=page_size,
76+
):
77+
for entry in page.iterate_metric_samples():
78+
yield entry
79+
80+
async def components_data_dict(
81+
components_data_iter: AsyncGenerator[MetricSample, None]
82+
) -> dict[int, dict[int, dict[datetime, dict[Metric, float]]]]:
83+
"""Convert components data iterator into a single dict.
84+
85+
The nesting structure is:
86+
{
87+
microgrid_id: {
88+
component_id: {
89+
timestamp: {
90+
metric: value
91+
}
92+
}
93+
}
94+
}
95+
96+
Args:
97+
components_data_iter: async generator
98+
99+
Returns:
100+
Single dict with with all components data
101+
"""
102+
ret: dict[int, dict[int, dict[datetime, dict[Metric, float]]]] = {}
103+
104+
async for ts, mid, cid, met, value in components_data_iter:
105+
if mid not in ret:
106+
ret[mid] = {}
107+
if cid not in ret[mid]:
108+
ret[mid][cid] = {}
109+
if ts not in ret[mid][cid]:
110+
ret[mid][cid][ts] = {}
111+
112+
ret[mid][cid][ts][met] = value
113+
114+
return ret
115+
116+
print("########################################################")
117+
print("Iterate over generator")
118+
async for msample in components_data_iter():
119+
print("Received:", msample)
120+
121+
print("########################################################")
122+
print("Dumping all data as a single dict")
123+
dct = await components_data_dict(components_data_iter())
124+
pprint(dct)
125+
126+
print("########################################################")
127+
print("Turn data into a pandas DataFrame")
128+
data = [cd async for cd in components_data_iter()]
129+
df = pd.DataFrame(data).set_index("timestamp")
130+
pprint(df)
131+
132+
133+
if __name__ == "__main__":
134+
parser = argparse.ArgumentParser()
135+
parser.add_argument("microgrid_id", type=int, help="Microgrid ID")
136+
parser.add_argument("component_id", type=int, help="Component ID")
137+
138+
args = parser.parse_args()
139+
asyncio.run(main(args.microgrid_id, args.component_id))

pyproject.toml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ dev-mypy = [
6464
"types-Markdown == 3.4.2.10",
6565
# For checking the noxfile, docs/ script, and tests
6666
"frequenz-client-reporting[dev-mkdocs,dev-noxfile,dev-pytest]",
67+
"pandas-stubs >= 2, < 3", # Only required for example
6768
]
6869
dev-noxfile = [
6970
"nox == 2023.4.22",
@@ -73,6 +74,7 @@ dev-pylint = [
7374
"pylint == 3.0.2",
7475
# For checking the noxfile, docs/ script, and tests
7576
"frequenz-client-reporting[dev-mkdocs,dev-noxfile,dev-pytest]",
77+
"pandas >= 2, < 3", # Only required for example
7678
]
7779
dev-pytest = [
7880
"pytest == 8.0.0",
@@ -84,6 +86,10 @@ dev-pytest = [
8486
dev = [
8587
"frequenz-client-reporting[dev-mkdocs,dev-flake8,dev-formatting,dev-mkdocs,dev-mypy,dev-noxfile,dev-pylint,dev-pytest]",
8688
]
89+
examples = [
90+
"grpcio >= 1.51.1, < 2",
91+
"pandas >= 2, < 3",
92+
]
8793

8894
[project.urls]
8995
Documentation = "https://frequenz-floss.github.io/frequenz-client-reporting-python/"

0 commit comments

Comments
 (0)