Skip to content

Commit b967671

Browse files
committed
Add ComponentDataSamples
Signed-off-by: Leandro Lucarella <[email protected]>
1 parent c9ad6f6 commit b967671

File tree

4 files changed

+498
-0
lines changed

4 files changed

+498
-0
lines changed

src/frequenz/client/microgrid/component/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
from ._connection import ComponentConnection
1919
from ._converter import Converter
2020
from ._crypto_miner import CryptoMiner
21+
from ._data_samples import ComponentDataSamples
2122
from ._electrolyzer import Electrolyzer
2223
from ._ev_charger import (
2324
AcEvCharger,
@@ -70,6 +71,7 @@
7071
"Component",
7172
"ComponentCategory",
7273
"ComponentConnection",
74+
"ComponentDataSamples",
7375
"ComponentErrorCode",
7476
"ComponentStateCode",
7577
"ComponentStateSample",
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# License: MIT
2+
# Copyright © 2025 Frequenz Energy-as-a-Service GmbH
3+
4+
"""Definition of a component data aggregate."""
5+
6+
from dataclasses import dataclass
7+
8+
from frequenz.client.common.microgrid.components import ComponentId
9+
10+
from ..metrics._sample import MetricSample
11+
from ._state_sample import ComponentStateSample
12+
13+
14+
@dataclass(frozen=True, kw_only=True)
15+
class ComponentDataSamples:
16+
"""An aggregate of multiple metrics, states, and errors of a component."""
17+
18+
component_id: ComponentId
19+
"""The unique identifier of the component."""
20+
21+
metric_samples: list[MetricSample]
22+
"""The metrics sampled from the component."""
23+
24+
states: list[ComponentStateSample]
25+
"""The states sampled from the component."""
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
# License: MIT
2+
# Copyright © 2025 Frequenz Energy-as-a-Service GmbH
3+
4+
"""Loading of ComponentDataSamples objects from protobuf messages."""
5+
6+
7+
import logging
8+
from functools import partial
9+
10+
from frequenz.api.common.v1.microgrid.components import components_pb2
11+
from frequenz.client.common.microgrid.components import ComponentId
12+
13+
from ..metrics._sample_proto import metric_sample_from_proto_with_issues
14+
from ._data_samples import ComponentDataSamples
15+
from ._state_sample_proto import component_state_sample_from_proto
16+
17+
_logger = logging.getLogger(__name__)
18+
19+
20+
def component_data_samples_from_proto(
21+
message: components_pb2.ComponentData,
22+
) -> ComponentDataSamples:
23+
"""Convert a protobuf component data message to a component data object.
24+
25+
Args:
26+
message: The protobuf message to convert.
27+
28+
Returns:
29+
The resulting `ComponentDataSamples` object.
30+
"""
31+
major_issues: list[str] = []
32+
minor_issues: list[str] = []
33+
34+
samples = component_data_samples_from_proto_with_issues(
35+
message, major_issues=major_issues, minor_issues=minor_issues
36+
)
37+
38+
# This approach to logging issues might be too noisy. Samples are received
39+
# very often, and sometimes can remain unchanged for a long time, leading to
40+
# repeated log messages. We might need to adjust the logging strategy
41+
# in the future.
42+
if major_issues:
43+
_logger.warning(
44+
"Found issues in component data samples: %s | Protobuf message:\n%s",
45+
", ".join(major_issues),
46+
message,
47+
)
48+
49+
if minor_issues:
50+
_logger.debug(
51+
"Found minor issues in component data samples: %s | Protobuf message:\n%s",
52+
", ".join(minor_issues),
53+
message,
54+
)
55+
56+
return samples
57+
58+
59+
def component_data_samples_from_proto_with_issues(
60+
message: components_pb2.ComponentData,
61+
*,
62+
major_issues: list[str],
63+
minor_issues: list[str],
64+
) -> ComponentDataSamples:
65+
"""Convert a protobuf component data message to a component data object collecting issues.
66+
67+
Args:
68+
message: The protobuf message to convert.
69+
major_issues: A list to append major issues to.
70+
minor_issues: A list to append minor issues to.
71+
72+
Returns:
73+
The resulting `ComponentDataSamples` object.
74+
"""
75+
return ComponentDataSamples(
76+
component_id=ComponentId(message.component_id),
77+
metric_samples=list(
78+
map(
79+
partial(
80+
metric_sample_from_proto_with_issues,
81+
major_issues=major_issues,
82+
minor_issues=minor_issues,
83+
),
84+
message.metric_samples,
85+
)
86+
),
87+
states=list(map(component_state_sample_from_proto, message.states)),
88+
)

0 commit comments

Comments
 (0)