frequenz-client-common 0.2.0__tar.gz → 0.3.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (24) hide show
  1. {frequenz-client-common-0.2.0/src/frequenz_client_common.egg-info → frequenz_client_common-0.3.2}/PKG-INFO +37 -3
  2. frequenz_client_common-0.3.2/RELEASE_NOTES.md +19 -0
  3. {frequenz-client-common-0.2.0 → frequenz_client_common-0.3.2}/pyproject.toml +45 -27
  4. {frequenz-client-common-0.2.0 → frequenz_client_common-0.3.2}/src/frequenz/client/common/metric/__init__.py +13 -2
  5. frequenz_client_common-0.3.2/src/frequenz/client/common/microgrid/__init__.py +18 -0
  6. frequenz_client_common-0.3.2/src/frequenz/client/common/microgrid/components/__init__.py +362 -0
  7. frequenz_client_common-0.3.2/src/frequenz/client/common/microgrid/sensors.py +13 -0
  8. {frequenz-client-common-0.2.0 → frequenz_client_common-0.3.2}/src/frequenz/client/common/pagination/__init__.py +2 -2
  9. {frequenz-client-common-0.2.0 → frequenz_client_common-0.3.2/src/frequenz_client_common.egg-info}/PKG-INFO +37 -3
  10. {frequenz-client-common-0.2.0 → frequenz_client_common-0.3.2}/src/frequenz_client_common.egg-info/SOURCES.txt +1 -0
  11. frequenz_client_common-0.3.2/src/frequenz_client_common.egg-info/requires.txt +49 -0
  12. frequenz-client-common-0.2.0/RELEASE_NOTES.md +0 -5
  13. frequenz-client-common-0.2.0/src/frequenz/client/common/microgrid/__init__.py +0 -4
  14. frequenz-client-common-0.2.0/src/frequenz/client/common/microgrid/components/__init__.py +0 -67
  15. frequenz-client-common-0.2.0/src/frequenz_client_common.egg-info/requires.txt +0 -47
  16. {frequenz-client-common-0.2.0 → frequenz_client_common-0.3.2}/LICENSE +0 -0
  17. {frequenz-client-common-0.2.0 → frequenz_client_common-0.3.2}/MANIFEST.in +0 -0
  18. {frequenz-client-common-0.2.0 → frequenz_client_common-0.3.2}/README.md +0 -0
  19. {frequenz-client-common-0.2.0 → frequenz_client_common-0.3.2}/setup.cfg +0 -0
  20. {frequenz-client-common-0.2.0 → frequenz_client_common-0.3.2}/src/frequenz/client/common/__init__.py +0 -0
  21. {frequenz-client-common-0.2.0 → frequenz_client_common-0.3.2}/src/frequenz/client/common/conftest.py +0 -0
  22. {frequenz-client-common-0.2.0 → frequenz_client_common-0.3.2}/src/frequenz/client/common/py.typed +0 -0
  23. {frequenz-client-common-0.2.0 → frequenz_client_common-0.3.2}/src/frequenz_client_common.egg-info/dependency_links.txt +0 -0
  24. {frequenz-client-common-0.2.0 → frequenz_client_common-0.3.2}/src/frequenz_client_common.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: frequenz-client-common
3
- Version: 0.2.0
3
+ Version: 0.3.2
4
4
  Summary: Common code and utilities for Frequenz API clients
5
5
  Author-email: Frequenz Energy-as-a-Service GmbH <floss@frequenz.com>
6
6
  License: MIT
@@ -19,15 +19,49 @@ Classifier: Topic :: Software Development :: Libraries
19
19
  Classifier: Typing :: Typed
20
20
  Requires-Python: <4,>=3.11
21
21
  Description-Content-Type: text/markdown
22
+ License-File: LICENSE
23
+ Requires-Dist: typing-extensions<5,>=4.13.0
24
+ Requires-Dist: frequenz-api-common<7,>=0.6.0
25
+ Requires-Dist: frequenz-core<2,>=1.0.0
22
26
  Provides-Extra: dev-flake8
27
+ Requires-Dist: flake8==7.2.0; extra == "dev-flake8"
28
+ Requires-Dist: flake8-docstrings==1.7.0; extra == "dev-flake8"
29
+ Requires-Dist: flake8-pyproject==1.2.3; extra == "dev-flake8"
30
+ Requires-Dist: pydoclint==0.6.6; extra == "dev-flake8"
31
+ Requires-Dist: pydocstyle==6.3.0; extra == "dev-flake8"
23
32
  Provides-Extra: dev-formatting
33
+ Requires-Dist: black==25.1.0; extra == "dev-formatting"
34
+ Requires-Dist: isort==6.0.1; extra == "dev-formatting"
24
35
  Provides-Extra: dev-mkdocs
36
+ Requires-Dist: Markdown==3.8; extra == "dev-mkdocs"
37
+ Requires-Dist: black==25.1.0; extra == "dev-mkdocs"
38
+ Requires-Dist: mike==2.1.3; extra == "dev-mkdocs"
39
+ Requires-Dist: mkdocs-gen-files==0.5.0; extra == "dev-mkdocs"
40
+ Requires-Dist: mkdocs-literate-nav==0.6.2; extra == "dev-mkdocs"
41
+ Requires-Dist: mkdocs-macros-plugin==1.3.7; extra == "dev-mkdocs"
42
+ Requires-Dist: mkdocs-material==9.6.12; extra == "dev-mkdocs"
43
+ Requires-Dist: mkdocstrings[python]==0.29.1; extra == "dev-mkdocs"
44
+ Requires-Dist: mkdocstrings-python==1.16.10; extra == "dev-mkdocs"
45
+ Requires-Dist: frequenz-repo-config[lib]==0.13.3; extra == "dev-mkdocs"
25
46
  Provides-Extra: dev-mypy
47
+ Requires-Dist: mypy==1.15.0; extra == "dev-mypy"
48
+ Requires-Dist: types-Markdown==3.8.0.20250415; extra == "dev-mypy"
49
+ Requires-Dist: frequenz-client-common[dev-mkdocs,dev-noxfile,dev-pytest]; extra == "dev-mypy"
26
50
  Provides-Extra: dev-noxfile
51
+ Requires-Dist: nox==2025.5.1; extra == "dev-noxfile"
52
+ Requires-Dist: frequenz-repo-config[lib]==0.13.3; extra == "dev-noxfile"
27
53
  Provides-Extra: dev-pylint
54
+ Requires-Dist: pylint==3.3.6; extra == "dev-pylint"
55
+ Requires-Dist: frequenz-client-common[dev-mkdocs,dev-noxfile,dev-pytest]; extra == "dev-pylint"
28
56
  Provides-Extra: dev-pytest
57
+ Requires-Dist: pytest==8.3.5; extra == "dev-pytest"
58
+ Requires-Dist: frequenz-repo-config[extra-lint-examples]==0.13.3; extra == "dev-pytest"
59
+ Requires-Dist: pytest-mock==3.14.0; extra == "dev-pytest"
60
+ Requires-Dist: pytest-asyncio==0.26.0; extra == "dev-pytest"
61
+ Requires-Dist: async-solipsism==0.7; extra == "dev-pytest"
29
62
  Provides-Extra: dev
30
- License-File: LICENSE
63
+ Requires-Dist: frequenz-client-common[dev-flake8,dev-formatting,dev-mkdocs,dev-mypy,dev-noxfile,dev-pylint,dev-pytest]; extra == "dev"
64
+ Dynamic: license-file
31
65
 
32
66
  # Frequenz Client Common Library
33
67
 
@@ -0,0 +1,19 @@
1
+ # Frequenz Client Common Library Release Notes
2
+
3
+ ## Summary
4
+
5
+ This release replaces the failed v0.3.1 release.
6
+
7
+ ## Upgrading
8
+
9
+ - The `typing-extensions` dependency minimum version was bumped to 4.13 to support Python 3.12.
10
+
11
+ ## New Features
12
+
13
+ - New `BaseId` class to create unique IDs for entities in the system.
14
+ - New ID classes for microgrid-related entities:
15
+
16
+ * `EnterpriseId`
17
+ * `MicrogridId`
18
+ * `ComponentId`
19
+ * `SensorId`
@@ -3,9 +3,9 @@
3
3
 
4
4
  [build-system]
5
5
  requires = [
6
- "setuptools == 68.1.0",
7
- "setuptools_scm[toml] == 7.1.0",
8
- "frequenz-repo-config[lib] == 0.9.1",
6
+ "setuptools == 80.3.1",
7
+ "setuptools_scm[toml] == 8.3.1",
8
+ "frequenz-repo-config[lib] == 0.13.3",
9
9
  ]
10
10
  build-backend = "setuptools.build_meta"
11
11
 
@@ -26,8 +26,9 @@ classifiers = [
26
26
  ]
27
27
  requires-python = ">= 3.11, < 4"
28
28
  dependencies = [
29
- "typing-extensions >= 4.5.0, < 5",
29
+ "typing-extensions >= 4.13.0, < 5",
30
30
  "frequenz-api-common >= 0.6.0, < 7",
31
+ "frequenz-core >= 1.0.0, < 2",
31
32
  ]
32
33
  dynamic = ["version"]
33
34
 
@@ -37,45 +38,43 @@ email = "floss@frequenz.com"
37
38
 
38
39
  [project.optional-dependencies]
39
40
  dev-flake8 = [
40
- "flake8 == 7.0.0",
41
+ "flake8 == 7.2.0",
41
42
  "flake8-docstrings == 1.7.0",
42
- "flake8-pyproject == 1.2.3", # For reading the flake8 config from pyproject.toml
43
- "pydoclint == 0.4.1",
43
+ "flake8-pyproject == 1.2.3", # For reading the flake8 config from pyproject.toml
44
+ "pydoclint == 0.6.6",
44
45
  "pydocstyle == 6.3.0",
45
46
  ]
46
- dev-formatting = ["black == 24.4.2", "isort == 5.13.2"]
47
+ dev-formatting = ["black == 25.1.0", "isort == 6.0.1"]
47
48
  dev-mkdocs = [
48
- "black == 24.4.2",
49
- "Markdown==3.6",
50
- "mike == 2.0.0",
49
+ "Markdown == 3.8",
50
+ "black == 25.1.0",
51
+ "mike == 2.1.3",
51
52
  "mkdocs-gen-files == 0.5.0",
52
- "mkdocs-literate-nav == 0.6.1",
53
- "mkdocs-macros-plugin == 1.0.5",
54
- "mkdocs-material == 9.5.20",
55
- "mkdocstrings[python] == 0.25.0",
56
- "frequenz-repo-config[lib] == 0.9.1",
53
+ "mkdocs-literate-nav == 0.6.2",
54
+ "mkdocs-macros-plugin == 1.3.7",
55
+ "mkdocs-material == 9.6.12",
56
+ "mkdocstrings[python] == 0.29.1",
57
+ "mkdocstrings-python == 1.16.10",
58
+ "frequenz-repo-config[lib] == 0.13.3",
57
59
  ]
58
60
  dev-mypy = [
59
- "mypy == 1.10.0",
60
- "types-Markdown == 3.6.0.20240316",
61
+ "mypy == 1.15.0",
62
+ "types-Markdown == 3.8.0.20250415",
61
63
  # For checking the noxfile, docs/ script, and tests
62
64
  "frequenz-client-common[dev-mkdocs,dev-noxfile,dev-pytest]",
63
65
  ]
64
- dev-noxfile = [
65
- "nox == 2024.4.15",
66
- "frequenz-repo-config[lib] == 0.9.1",
67
- ]
66
+ dev-noxfile = ["nox == 2025.5.1", "frequenz-repo-config[lib] == 0.13.3"]
68
67
  dev-pylint = [
69
- "pylint == 3.1.0",
68
+ "pylint == 3.3.6",
70
69
  # For checking the noxfile, docs/ script, and tests
71
70
  "frequenz-client-common[dev-mkdocs,dev-noxfile,dev-pytest]",
72
71
  ]
73
72
  dev-pytest = [
74
- "pytest == 8.2.0",
75
- "frequenz-repo-config[extra-lint-examples] == 0.9.1",
73
+ "pytest == 8.3.5",
74
+ "frequenz-repo-config[extra-lint-examples] == 0.13.3",
76
75
  "pytest-mock == 3.14.0",
77
- "pytest-asyncio == 0.23.6",
78
- "async-solipsism == 0.6",
76
+ "pytest-asyncio == 0.26.0",
77
+ "async-solipsism == 0.7",
79
78
  ]
80
79
  dev = [
81
80
  "frequenz-client-common[dev-mkdocs,dev-flake8,dev-formatting,dev-mkdocs,dev-mypy,dev-noxfile,dev-pylint,dev-pytest]",
@@ -131,17 +130,36 @@ disable = [
131
130
  # pylint's unsubscriptable check is buggy and is not needed because
132
131
  # it is a type-check, for which we already have mypy.
133
132
  "unsubscriptable-object",
133
+ # Checked by mypy
134
+ "no-member",
135
+ "possibly-used-before-assignment",
136
+ "no-name-in-module",
134
137
  # Checked by flake8
138
+ "f-string-without-interpolation",
135
139
  "redefined-outer-name",
136
140
  "unused-import",
137
141
  "line-too-long",
142
+ "missing-function-docstring",
138
143
  "unused-variable",
139
144
  "unnecessary-lambda-assignment",
140
145
  ]
141
146
 
142
147
  [tool.pytest.ini_options]
148
+ addopts = "-vv"
149
+ filterwarnings = [
150
+ "error",
151
+ "once::DeprecationWarning",
152
+ "once::PendingDeprecationWarning",
153
+ # We ignore warnings about protobuf gencode version being one version older
154
+ # than the current version, as this is supported by protobuf, and we expect to
155
+ # have such cases. If we go too far, we will get a proper error anyways.
156
+ # We use a raw string (single quotes) to avoid the need to escape special
157
+ # characters as this is a regex.
158
+ 'ignore:Protobuf gencode version .*exactly one major version older.*:UserWarning',
159
+ ]
143
160
  testpaths = ["tests", "src"]
144
161
  asyncio_mode = "auto"
162
+ asyncio_default_fixture_loop_scope = "function"
145
163
  required_plugins = ["pytest-asyncio", "pytest-mock"]
146
164
 
147
165
  [tool.mypy]
@@ -13,7 +13,18 @@ from frequenz.api.common.v1.metrics.metric_sample_pb2 import Metric as PBMetric
13
13
 
14
14
 
15
15
  class Metric(Enum):
16
- """List of supported metrics."""
16
+ """List of supported metrics.
17
+
18
+ AC energy metrics information:
19
+ * This energy metric is reported directly from the component, and not a
20
+ result of aggregations in our systems. If a component does not have this
21
+ metric, this field cannot be populated.
22
+ * Components that provide energy metrics reset this metric from time to
23
+ time. This behaviour is specific to each component model. E.g., some
24
+ components reset it on UTC 00:00:00.
25
+ * This energy metric does not specify the timestamp since when the energy
26
+ was being accumulated, and therefore can be inconsistent.
27
+ """
17
28
 
18
29
  # Default value
19
30
  UNSPECIFIED = PBMetric.METRIC_UNSPECIFIED
@@ -57,7 +68,7 @@ class Metric(Enum):
57
68
  AC_POWER_FACTOR_PHASE_2 = PBMetric.METRIC_AC_POWER_FACTOR_PHASE_2
58
69
  AC_POWER_FACTOR_PHASE_3 = PBMetric.METRIC_AC_POWER_FACTOR_PHASE_3
59
70
 
60
- # AC energy metrics
71
+ # AC energy metrics - Please be careful when using and check Enum docs
61
72
  AC_APPARENT_ENERGY = PBMetric.METRIC_AC_APPARENT_ENERGY
62
73
  AC_APPARENT_ENERGY_PHASE_1 = PBMetric.METRIC_AC_APPARENT_ENERGY_PHASE_1
63
74
  AC_APPARENT_ENERGY_PHASE_2 = PBMetric.METRIC_AC_APPARENT_ENERGY_PHASE_2
@@ -0,0 +1,18 @@
1
+ # License: MIT
2
+ # Copyright © 2023 Frequenz Energy-as-a-Service GmbH
3
+
4
+ """Frequenz microgrid definition."""
5
+
6
+ from typing import final
7
+
8
+ from frequenz.core.id import BaseId
9
+
10
+
11
+ @final
12
+ class EnterpriseId(BaseId, str_prefix="EID"):
13
+ """A unique identifier for an enterprise account."""
14
+
15
+
16
+ @final
17
+ class MicrogridId(BaseId, str_prefix="MID"):
18
+ """A unique identifier for a microgrid."""
@@ -0,0 +1,362 @@
1
+ # License: MIT
2
+ # Copyright © 2022 Frequenz Energy-as-a-Service GmbH
3
+
4
+ """Defines the components that can be used in a microgrid."""
5
+
6
+ from __future__ import annotations
7
+
8
+ from enum import Enum
9
+ from typing import final
10
+
11
+ # pylint: disable=no-name-in-module
12
+ from frequenz.api.common.v1.microgrid.components.components_pb2 import (
13
+ ComponentCategory as PBComponentCategory,
14
+ )
15
+ from frequenz.api.common.v1.microgrid.components.components_pb2 import (
16
+ ComponentErrorCode as PBComponentErrorCode,
17
+ )
18
+ from frequenz.api.common.v1.microgrid.components.components_pb2 import (
19
+ ComponentStateCode as PBComponentStateCode,
20
+ )
21
+ from frequenz.core.id import BaseId
22
+
23
+ # pylint: enable=no-name-in-module
24
+
25
+
26
+ @final
27
+ class ComponentId(BaseId, str_prefix="CID"):
28
+ """A unique identifier for a microgrid component."""
29
+
30
+
31
+ class ComponentCategory(Enum):
32
+ """Possible types of microgrid component."""
33
+
34
+ UNSPECIFIED = PBComponentCategory.COMPONENT_CATEGORY_UNSPECIFIED
35
+ """An unknown component category.
36
+
37
+ Useful for error handling, and marking unknown components in
38
+ a list of components with otherwise known categories.
39
+ """
40
+
41
+ GRID = PBComponentCategory.COMPONENT_CATEGORY_GRID
42
+ """The point where the local microgrid is connected to the grid."""
43
+
44
+ METER = PBComponentCategory.COMPONENT_CATEGORY_METER
45
+ """A meter, for measuring electrical metrics, e.g., current, voltage, etc."""
46
+
47
+ INVERTER = PBComponentCategory.COMPONENT_CATEGORY_INVERTER
48
+ """An electricity generator, with batteries or solar energy."""
49
+
50
+ BATTERY = PBComponentCategory.COMPONENT_CATEGORY_BATTERY
51
+ """A storage system for electrical energy, used by inverters."""
52
+
53
+ EV_CHARGER = PBComponentCategory.COMPONENT_CATEGORY_EV_CHARGER
54
+ """A station for charging electrical vehicles."""
55
+
56
+ CHP = PBComponentCategory.COMPONENT_CATEGORY_CHP
57
+ """A heat and power combustion plant (CHP stands for combined heat and power)."""
58
+
59
+ @classmethod
60
+ def from_proto(
61
+ cls, component_category: PBComponentCategory.ValueType
62
+ ) -> ComponentCategory:
63
+ """Convert a protobuf ComponentCategory message to ComponentCategory enum.
64
+
65
+ Args:
66
+ component_category: protobuf enum to convert
67
+
68
+ Returns:
69
+ Enum value corresponding to the protobuf message.
70
+ """
71
+ if not any(t.value == component_category for t in ComponentCategory):
72
+ return ComponentCategory.UNSPECIFIED
73
+ return cls(component_category)
74
+
75
+ def to_proto(self) -> PBComponentCategory.ValueType:
76
+ """Convert a ComponentCategory enum to protobuf ComponentCategory message.
77
+
78
+ Returns:
79
+ Enum value corresponding to the protobuf message.
80
+ """
81
+ return self.value
82
+
83
+
84
+ class ComponentStateCode(Enum):
85
+ """All possible states of a microgrid component."""
86
+
87
+ UNSPECIFIED = PBComponentStateCode.COMPONENT_STATE_CODE_UNSPECIFIED
88
+ """Default value when the component state is not explicitly set."""
89
+
90
+ UNKNOWN = PBComponentStateCode.COMPONENT_STATE_CODE_UNKNOWN
91
+ """State when the component is in an unknown or undefined condition.
92
+
93
+ This is used when the sender is unable to classify the component into any
94
+ other state.
95
+ """
96
+ SWITCHING_OFF = PBComponentStateCode.COMPONENT_STATE_CODE_SWITCHING_OFF
97
+ """State when the component is in the process of switching off."""
98
+
99
+ OFF = PBComponentStateCode.COMPONENT_STATE_CODE_OFF
100
+ """State when the component has successfully switched off."""
101
+
102
+ SWITCHING_ON = PBComponentStateCode.COMPONENT_STATE_CODE_SWITCHING_ON
103
+ """State when the component is in the process of switching on from an off state."""
104
+
105
+ STANDBY = PBComponentStateCode.COMPONENT_STATE_CODE_STANDBY
106
+ """State when the component is in standby mode, and not immediately ready for operation."""
107
+
108
+ READY = PBComponentStateCode.COMPONENT_STATE_CODE_READY
109
+ """State when the component is fully operational and ready for use."""
110
+
111
+ CHARGING = PBComponentStateCode.COMPONENT_STATE_CODE_CHARGING
112
+ """State when the component is actively consuming energy."""
113
+
114
+ DISCHARGING = PBComponentStateCode.COMPONENT_STATE_CODE_DISCHARGING
115
+ """State when the component is actively producing or releasing energy."""
116
+
117
+ ERROR = PBComponentStateCode.COMPONENT_STATE_CODE_ERROR
118
+ """State when the component is in an error state and may need attention."""
119
+
120
+ EV_CHARGING_CABLE_UNPLUGGED = (
121
+ PBComponentStateCode.COMPONENT_STATE_CODE_EV_CHARGING_CABLE_UNPLUGGED
122
+ )
123
+ """The Electric Vehicle (EV) charging cable is unplugged from the charging station."""
124
+
125
+ EV_CHARGING_CABLE_PLUGGED_AT_STATION = (
126
+ PBComponentStateCode.COMPONENT_STATE_CODE_EV_CHARGING_CABLE_PLUGGED_AT_STATION
127
+ )
128
+ """The EV charging cable is plugged into the charging station."""
129
+
130
+ EV_CHARGING_CABLE_PLUGGED_AT_EV = (
131
+ PBComponentStateCode.COMPONENT_STATE_CODE_EV_CHARGING_CABLE_PLUGGED_AT_EV
132
+ )
133
+ """The EV charging cable is plugged into the vehicle."""
134
+
135
+ EV_CHARGING_CABLE_LOCKED_AT_STATION = (
136
+ PBComponentStateCode.COMPONENT_STATE_CODE_EV_CHARGING_CABLE_LOCKED_AT_STATION
137
+ )
138
+ """The EV charging cable is locked at the charging station end, indicating
139
+ readiness for charging."""
140
+
141
+ EV_CHARGING_CABLE_LOCKED_AT_EV = (
142
+ PBComponentStateCode.COMPONENT_STATE_CODE_EV_CHARGING_CABLE_LOCKED_AT_EV
143
+ )
144
+ """The EV charging cable is locked at the vehicle end, indicating that charging is active."""
145
+
146
+ RELAY_OPEN = PBComponentStateCode.COMPONENT_STATE_CODE_RELAY_OPEN
147
+ """The relay is in an open state, meaning no current can flow through."""
148
+
149
+ RELAY_CLOSED = PBComponentStateCode.COMPONENT_STATE_CODE_RELAY_CLOSED
150
+ """The relay is in a closed state, allowing current to flow."""
151
+
152
+ PRECHARGER_OPEN = PBComponentStateCode.COMPONENT_STATE_CODE_PRECHARGER_OPEN
153
+ """The precharger circuit is open, meaning it's not currently active."""
154
+
155
+ PRECHARGER_PRECHARGING = (
156
+ PBComponentStateCode.COMPONENT_STATE_CODE_PRECHARGER_PRECHARGING
157
+ )
158
+ """The precharger is in a precharging state, preparing the main circuit for activation."""
159
+
160
+ PRECHARGER_CLOSED = PBComponentStateCode.COMPONENT_STATE_CODE_PRECHARGER_CLOSED
161
+ """The precharger circuit is closed, allowing full current to flow to the main circuit."""
162
+
163
+ @classmethod
164
+ def from_proto(
165
+ cls, component_state: PBComponentStateCode.ValueType
166
+ ) -> ComponentStateCode:
167
+ """Convert a protobuf ComponentStateCode message to ComponentStateCode enum.
168
+
169
+ Args:
170
+ component_state: protobuf enum to convert
171
+
172
+ Returns:
173
+ Enum value corresponding to the protobuf message.
174
+ """
175
+ if not any(c.value == component_state for c in ComponentStateCode):
176
+ return ComponentStateCode.UNSPECIFIED
177
+ return cls(component_state)
178
+
179
+ def to_proto(self) -> PBComponentStateCode.ValueType:
180
+ """Convert a ComponentStateCode enum to protobuf ComponentStateCode message.
181
+
182
+ Returns:
183
+ Enum value corresponding to the protobuf message.
184
+ """
185
+ return self.value
186
+
187
+
188
+ class ComponentErrorCode(Enum):
189
+ """All possible errors that can occur across all microgrid component categories."""
190
+
191
+ UNSPECIFIED = PBComponentErrorCode.COMPONENT_ERROR_CODE_UNSPECIFIED
192
+ """Default value. No specific error is specified."""
193
+
194
+ UNKNOWN = PBComponentErrorCode.COMPONENT_ERROR_CODE_UNKNOWN
195
+ """The component is reporting an unknown or an undefined error, and the sender
196
+ cannot parse the component error to any of the variants below."""
197
+
198
+ SWITCH_ON_FAULT = PBComponentErrorCode.COMPONENT_ERROR_CODE_SWITCH_ON_FAULT
199
+ """Error indicating that the component could not be switched on."""
200
+
201
+ UNDERVOLTAGE = PBComponentErrorCode.COMPONENT_ERROR_CODE_UNDERVOLTAGE
202
+ """Error indicating that the component is operating under the minimum rated
203
+ voltage."""
204
+
205
+ OVERVOLTAGE = PBComponentErrorCode.COMPONENT_ERROR_CODE_OVERVOLTAGE
206
+ """Error indicating that the component is operating over the maximum rated
207
+ voltage."""
208
+
209
+ OVERCURRENT = PBComponentErrorCode.COMPONENT_ERROR_CODE_OVERCURRENT
210
+ """Error indicating that the component is drawing more current than the
211
+ maximum rated value."""
212
+
213
+ OVERCURRENT_CHARGING = (
214
+ PBComponentErrorCode.COMPONENT_ERROR_CODE_OVERCURRENT_CHARGING
215
+ )
216
+ """Error indicating that the component's consumption current is over the
217
+ maximum rated value during charging."""
218
+
219
+ OVERCURRENT_DISCHARGING = (
220
+ PBComponentErrorCode.COMPONENT_ERROR_CODE_OVERCURRENT_DISCHARGING
221
+ )
222
+ """Error indicating that the component's production current is over the
223
+ maximum rated value during discharging."""
224
+
225
+ OVERTEMPERATURE = PBComponentErrorCode.COMPONENT_ERROR_CODE_OVERTEMPERATURE
226
+ """Error indicating that the component is operating over the maximum rated
227
+ temperature."""
228
+
229
+ UNDERTEMPERATURE = PBComponentErrorCode.COMPONENT_ERROR_CODE_UNDERTEMPERATURE
230
+ """Error indicating that the component is operating under the minimum rated
231
+ temperature."""
232
+
233
+ HIGH_HUMIDITY = PBComponentErrorCode.COMPONENT_ERROR_CODE_HIGH_HUMIDITY
234
+ """Error indicating that the component is exposed to high humidity levels over
235
+ the maximum rated value."""
236
+
237
+ FUSE_ERROR = PBComponentErrorCode.COMPONENT_ERROR_CODE_FUSE_ERROR
238
+ """Error indicating that the component's fuse has blown."""
239
+
240
+ PRECHARGE_ERROR = PBComponentErrorCode.COMPONENT_ERROR_CODE_PRECHARGE_ERROR
241
+ """Error indicating that the component's precharge unit has failed."""
242
+
243
+ PLAUSIBILITY_ERROR = PBComponentErrorCode.COMPONENT_ERROR_CODE_PLAUSIBILITY_ERROR
244
+ """Error indicating plausibility issues within the system involving this
245
+ component."""
246
+
247
+ UNDERVOLTAGE_SHUTDOWN = (
248
+ PBComponentErrorCode.COMPONENT_ERROR_CODE_UNDERVOLTAGE_SHUTDOWN
249
+ )
250
+ """Error indicating system shutdown due to undervoltage involving this
251
+ component."""
252
+
253
+ EV_UNEXPECTED_PILOT_FAILURE = (
254
+ PBComponentErrorCode.COMPONENT_ERROR_CODE_EV_UNEXPECTED_PILOT_FAILURE
255
+ )
256
+ """Error indicating unexpected pilot failure in an electric vehicle (EV)
257
+ component."""
258
+
259
+ FAULT_CURRENT = PBComponentErrorCode.COMPONENT_ERROR_CODE_FAULT_CURRENT
260
+ """Error indicating fault current detected in the component."""
261
+
262
+ SHORT_CIRCUIT = PBComponentErrorCode.COMPONENT_ERROR_CODE_SHORT_CIRCUIT
263
+ """Error indicating a short circuit detected in the component."""
264
+
265
+ CONFIG_ERROR = PBComponentErrorCode.COMPONENT_ERROR_CODE_CONFIG_ERROR
266
+ """Error indicating a configuration error related to the component."""
267
+
268
+ ILLEGAL_COMPONENT_STATE_CODE_REQUESTED = (
269
+ PBComponentErrorCode.COMPONENT_ERROR_CODE_ILLEGAL_COMPONENT_STATE_CODE_REQUESTED
270
+ )
271
+ """Error indicating an illegal state requested for the component."""
272
+
273
+ HARDWARE_INACCESSIBLE = (
274
+ PBComponentErrorCode.COMPONENT_ERROR_CODE_HARDWARE_INACCESSIBLE
275
+ )
276
+ """Error indicating that the hardware of the component is inaccessible."""
277
+
278
+ INTERNAL = PBComponentErrorCode.COMPONENT_ERROR_CODE_INTERNAL
279
+ """Error indicating an internal error within the component."""
280
+
281
+ UNAUTHORIZED = PBComponentErrorCode.COMPONENT_ERROR_CODE_UNAUTHORIZED
282
+ """Error indicating that the component is unauthorized to perform the
283
+ last requested action."""
284
+
285
+ EV_CHARGING_CABLE_UNPLUGGED_FROM_STATION = (
286
+ PBComponentErrorCode.COMPONENT_ERROR_CODE_EV_CHARGING_CABLE_UNPLUGGED_FROM_STATION
287
+ )
288
+ """Error indicating electric vehicle (EV) cable was abruptly unplugged from
289
+ the charging station."""
290
+
291
+ EV_CHARGING_CABLE_UNPLUGGED_FROM_EV = (
292
+ PBComponentErrorCode.COMPONENT_ERROR_CODE_EV_CHARGING_CABLE_UNPLUGGED_FROM_EV
293
+ )
294
+ """Error indicating electric vehicle (EV) cable was abruptly unplugged from
295
+ the vehicle."""
296
+
297
+ EV_CHARGING_CABLE_LOCK_FAILED = (
298
+ PBComponentErrorCode.COMPONENT_ERROR_CODE_EV_CHARGING_CABLE_LOCK_FAILED
299
+ )
300
+ """Error indicating electric vehicle (EV) cable lock failure."""
301
+
302
+ EV_CHARGING_CABLE_INVALID = (
303
+ PBComponentErrorCode.COMPONENT_ERROR_CODE_EV_CHARGING_CABLE_INVALID
304
+ )
305
+ """Error indicating an invalid electric vehicle (EV) cable."""
306
+
307
+ EV_CONSUMER_INCOMPATIBLE = (
308
+ PBComponentErrorCode.COMPONENT_ERROR_CODE_EV_CONSUMER_INCOMPATIBLE
309
+ )
310
+ """Error indicating an incompatible electric vehicle (EV) plug."""
311
+
312
+ BATTERY_IMBALANCE = PBComponentErrorCode.COMPONENT_ERROR_CODE_BATTERY_IMBALANCE
313
+ """Error indicating a battery system imbalance."""
314
+
315
+ BATTERY_LOW_SOH = PBComponentErrorCode.COMPONENT_ERROR_CODE_BATTERY_LOW_SOH
316
+ """Error indicating a low state of health (SOH) detected in the battery."""
317
+
318
+ BATTERY_BLOCK_ERROR = PBComponentErrorCode.COMPONENT_ERROR_CODE_BATTERY_BLOCK_ERROR
319
+ """Error indicating a battery block error."""
320
+
321
+ BATTERY_CONTROLLER_ERROR = (
322
+ PBComponentErrorCode.COMPONENT_ERROR_CODE_BATTERY_CONTROLLER_ERROR
323
+ )
324
+ """Error indicating a battery controller error."""
325
+
326
+ BATTERY_RELAY_ERROR = PBComponentErrorCode.COMPONENT_ERROR_CODE_BATTERY_RELAY_ERROR
327
+ """Error indicating a battery relay error."""
328
+
329
+ BATTERY_CALIBRATION_NEEDED = (
330
+ PBComponentErrorCode.COMPONENT_ERROR_CODE_BATTERY_CALIBRATION_NEEDED
331
+ )
332
+ """Error indicating that battery calibration is needed."""
333
+
334
+ RELAY_CYCLE_LIMIT_REACHED = (
335
+ PBComponentErrorCode.COMPONENT_ERROR_CODE_RELAY_CYCLE_LIMIT_REACHED
336
+ )
337
+ """Error indicating that the relays have been cycled for the maximum number of
338
+ times."""
339
+
340
+ @classmethod
341
+ def from_proto(
342
+ cls, component_error_code: PBComponentErrorCode.ValueType
343
+ ) -> ComponentErrorCode:
344
+ """Convert a protobuf ComponentErrorCode message to ComponentErrorCode enum.
345
+
346
+ Args:
347
+ component_error_code: protobuf enum to convert
348
+
349
+ Returns:
350
+ Enum value corresponding to the protobuf message.
351
+ """
352
+ if not any(c.value == component_error_code for c in ComponentErrorCode):
353
+ return ComponentErrorCode.UNSPECIFIED
354
+ return cls(component_error_code)
355
+
356
+ def to_proto(self) -> PBComponentErrorCode.ValueType:
357
+ """Convert a ComponentErrorCode enum to protobuf ComponentErrorCode message.
358
+
359
+ Returns:
360
+ Enum value corresponding to the protobuf message.
361
+ """
362
+ return self.value
@@ -0,0 +1,13 @@
1
+ # License: MIT
2
+ # Copyright © 2025 Frequenz Energy-as-a-Service GmbH
3
+
4
+ """Microgrid sensors."""
5
+
6
+ from typing import final
7
+
8
+ from frequenz.core.id import BaseId
9
+
10
+
11
+ @final
12
+ class SensorId(BaseId, str_prefix="SID"):
13
+ """A unique identifier for a microgrid sensor."""
@@ -19,10 +19,10 @@ from frequenz.api.common.v1.pagination.pagination_params_pb2 import PaginationPa
19
19
  class Params:
20
20
  """Parameters for paginating list requests."""
21
21
 
22
- page_size: int | None = None
22
+ page_size: int
23
23
  """The maximum number of results to be returned per request."""
24
24
 
25
- page_token: str | None = None
25
+ page_token: str
26
26
  """The token identifying a specific page of the list results."""
27
27
 
28
28
  @classmethod
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: frequenz-client-common
3
- Version: 0.2.0
3
+ Version: 0.3.2
4
4
  Summary: Common code and utilities for Frequenz API clients
5
5
  Author-email: Frequenz Energy-as-a-Service GmbH <floss@frequenz.com>
6
6
  License: MIT
@@ -19,15 +19,49 @@ Classifier: Topic :: Software Development :: Libraries
19
19
  Classifier: Typing :: Typed
20
20
  Requires-Python: <4,>=3.11
21
21
  Description-Content-Type: text/markdown
22
+ License-File: LICENSE
23
+ Requires-Dist: typing-extensions<5,>=4.13.0
24
+ Requires-Dist: frequenz-api-common<7,>=0.6.0
25
+ Requires-Dist: frequenz-core<2,>=1.0.0
22
26
  Provides-Extra: dev-flake8
27
+ Requires-Dist: flake8==7.2.0; extra == "dev-flake8"
28
+ Requires-Dist: flake8-docstrings==1.7.0; extra == "dev-flake8"
29
+ Requires-Dist: flake8-pyproject==1.2.3; extra == "dev-flake8"
30
+ Requires-Dist: pydoclint==0.6.6; extra == "dev-flake8"
31
+ Requires-Dist: pydocstyle==6.3.0; extra == "dev-flake8"
23
32
  Provides-Extra: dev-formatting
33
+ Requires-Dist: black==25.1.0; extra == "dev-formatting"
34
+ Requires-Dist: isort==6.0.1; extra == "dev-formatting"
24
35
  Provides-Extra: dev-mkdocs
36
+ Requires-Dist: Markdown==3.8; extra == "dev-mkdocs"
37
+ Requires-Dist: black==25.1.0; extra == "dev-mkdocs"
38
+ Requires-Dist: mike==2.1.3; extra == "dev-mkdocs"
39
+ Requires-Dist: mkdocs-gen-files==0.5.0; extra == "dev-mkdocs"
40
+ Requires-Dist: mkdocs-literate-nav==0.6.2; extra == "dev-mkdocs"
41
+ Requires-Dist: mkdocs-macros-plugin==1.3.7; extra == "dev-mkdocs"
42
+ Requires-Dist: mkdocs-material==9.6.12; extra == "dev-mkdocs"
43
+ Requires-Dist: mkdocstrings[python]==0.29.1; extra == "dev-mkdocs"
44
+ Requires-Dist: mkdocstrings-python==1.16.10; extra == "dev-mkdocs"
45
+ Requires-Dist: frequenz-repo-config[lib]==0.13.3; extra == "dev-mkdocs"
25
46
  Provides-Extra: dev-mypy
47
+ Requires-Dist: mypy==1.15.0; extra == "dev-mypy"
48
+ Requires-Dist: types-Markdown==3.8.0.20250415; extra == "dev-mypy"
49
+ Requires-Dist: frequenz-client-common[dev-mkdocs,dev-noxfile,dev-pytest]; extra == "dev-mypy"
26
50
  Provides-Extra: dev-noxfile
51
+ Requires-Dist: nox==2025.5.1; extra == "dev-noxfile"
52
+ Requires-Dist: frequenz-repo-config[lib]==0.13.3; extra == "dev-noxfile"
27
53
  Provides-Extra: dev-pylint
54
+ Requires-Dist: pylint==3.3.6; extra == "dev-pylint"
55
+ Requires-Dist: frequenz-client-common[dev-mkdocs,dev-noxfile,dev-pytest]; extra == "dev-pylint"
28
56
  Provides-Extra: dev-pytest
57
+ Requires-Dist: pytest==8.3.5; extra == "dev-pytest"
58
+ Requires-Dist: frequenz-repo-config[extra-lint-examples]==0.13.3; extra == "dev-pytest"
59
+ Requires-Dist: pytest-mock==3.14.0; extra == "dev-pytest"
60
+ Requires-Dist: pytest-asyncio==0.26.0; extra == "dev-pytest"
61
+ Requires-Dist: async-solipsism==0.7; extra == "dev-pytest"
29
62
  Provides-Extra: dev
30
- License-File: LICENSE
63
+ Requires-Dist: frequenz-client-common[dev-flake8,dev-formatting,dev-mkdocs,dev-mypy,dev-noxfile,dev-pylint,dev-pytest]; extra == "dev"
64
+ Dynamic: license-file
31
65
 
32
66
  # Frequenz Client Common Library
33
67
 
@@ -8,6 +8,7 @@ src/frequenz/client/common/conftest.py
8
8
  src/frequenz/client/common/py.typed
9
9
  src/frequenz/client/common/metric/__init__.py
10
10
  src/frequenz/client/common/microgrid/__init__.py
11
+ src/frequenz/client/common/microgrid/sensors.py
11
12
  src/frequenz/client/common/microgrid/components/__init__.py
12
13
  src/frequenz/client/common/pagination/__init__.py
13
14
  src/frequenz_client_common.egg-info/PKG-INFO
@@ -0,0 +1,49 @@
1
+ typing-extensions<5,>=4.13.0
2
+ frequenz-api-common<7,>=0.6.0
3
+ frequenz-core<2,>=1.0.0
4
+
5
+ [dev]
6
+ frequenz-client-common[dev-flake8,dev-formatting,dev-mkdocs,dev-mypy,dev-noxfile,dev-pylint,dev-pytest]
7
+
8
+ [dev-flake8]
9
+ flake8==7.2.0
10
+ flake8-docstrings==1.7.0
11
+ flake8-pyproject==1.2.3
12
+ pydoclint==0.6.6
13
+ pydocstyle==6.3.0
14
+
15
+ [dev-formatting]
16
+ black==25.1.0
17
+ isort==6.0.1
18
+
19
+ [dev-mkdocs]
20
+ Markdown==3.8
21
+ black==25.1.0
22
+ mike==2.1.3
23
+ mkdocs-gen-files==0.5.0
24
+ mkdocs-literate-nav==0.6.2
25
+ mkdocs-macros-plugin==1.3.7
26
+ mkdocs-material==9.6.12
27
+ mkdocstrings[python]==0.29.1
28
+ mkdocstrings-python==1.16.10
29
+ frequenz-repo-config[lib]==0.13.3
30
+
31
+ [dev-mypy]
32
+ mypy==1.15.0
33
+ types-Markdown==3.8.0.20250415
34
+ frequenz-client-common[dev-mkdocs,dev-noxfile,dev-pytest]
35
+
36
+ [dev-noxfile]
37
+ nox==2025.5.1
38
+ frequenz-repo-config[lib]==0.13.3
39
+
40
+ [dev-pylint]
41
+ pylint==3.3.6
42
+ frequenz-client-common[dev-mkdocs,dev-noxfile,dev-pytest]
43
+
44
+ [dev-pytest]
45
+ pytest==8.3.5
46
+ frequenz-repo-config[extra-lint-examples]==0.13.3
47
+ pytest-mock==3.14.0
48
+ pytest-asyncio==0.26.0
49
+ async-solipsism==0.7
@@ -1,5 +0,0 @@
1
- # Frequenz Client Common Library Release Notes
2
-
3
- ## Upgrading
4
-
5
- * Upgrading metric `__init__` to names from api-common release [v0.6.0](https://github.com/frequenz-floss/frequenz-api-common/releases/tag/v0.6.0)
@@ -1,4 +0,0 @@
1
- # License: MIT
2
- # Copyright © 2023 Frequenz Energy-as-a-Service GmbH
3
-
4
- """Frequenz microgrid definition."""
@@ -1,67 +0,0 @@
1
- # License: MIT
2
- # Copyright © 2022 Frequenz Energy-as-a-Service GmbH
3
-
4
- """Defines the components that can be used in a microgrid."""
5
- from __future__ import annotations
6
-
7
- from enum import Enum
8
-
9
- # pylint: disable=no-name-in-module
10
- from frequenz.api.common.v1.microgrid.components.components_pb2 import (
11
- ComponentCategory as PBComponentCategory,
12
- )
13
-
14
- # pylint: enable=no-name-in-module
15
-
16
-
17
- class ComponentCategory(Enum):
18
- """Possible types of microgrid component."""
19
-
20
- UNSPECIFIED = PBComponentCategory.COMPONENT_CATEGORY_UNSPECIFIED
21
- """An unknown component category.
22
-
23
- Useful for error handling, and marking unknown components in
24
- a list of components with otherwise known categories.
25
- """
26
-
27
- GRID = PBComponentCategory.COMPONENT_CATEGORY_GRID
28
- """The point where the local microgrid is connected to the grid."""
29
-
30
- METER = PBComponentCategory.COMPONENT_CATEGORY_METER
31
- """A meter, for measuring electrical metrics, e.g., current, voltage, etc."""
32
-
33
- INVERTER = PBComponentCategory.COMPONENT_CATEGORY_INVERTER
34
- """An electricity generator, with batteries or solar energy."""
35
-
36
- BATTERY = PBComponentCategory.COMPONENT_CATEGORY_BATTERY
37
- """A storage system for electrical energy, used by inverters."""
38
-
39
- EV_CHARGER = PBComponentCategory.COMPONENT_CATEGORY_EV_CHARGER
40
- """A station for charging electrical vehicles."""
41
-
42
- CHP = PBComponentCategory.COMPONENT_CATEGORY_CHP
43
- """A heat and power combustion plant (CHP stands for combined heat and power)."""
44
-
45
- @classmethod
46
- def from_proto(
47
- cls, component_category: PBComponentCategory.ValueType
48
- ) -> ComponentCategory:
49
- """Convert a protobuf ComponentCategory message to ComponentCategory enum.
50
-
51
- Args:
52
- component_category: protobuf enum to convert
53
-
54
- Returns:
55
- Enum value corresponding to the protobuf message.
56
- """
57
- if not any(t.value == component_category for t in ComponentCategory):
58
- return ComponentCategory.UNSPECIFIED
59
- return cls(component_category)
60
-
61
- def to_proto(self) -> PBComponentCategory.ValueType:
62
- """Convert a ComponentCategory enum to protobuf ComponentCategory message.
63
-
64
- Returns:
65
- Enum value corresponding to the protobuf message.
66
- """
67
- return self.value
@@ -1,47 +0,0 @@
1
- typing-extensions<5,>=4.5.0
2
- frequenz-api-common<7,>=0.6.0
3
-
4
- [dev]
5
- frequenz-client-common[dev-flake8,dev-formatting,dev-mkdocs,dev-mypy,dev-noxfile,dev-pylint,dev-pytest]
6
-
7
- [dev-flake8]
8
- flake8==7.0.0
9
- flake8-docstrings==1.7.0
10
- flake8-pyproject==1.2.3
11
- pydoclint==0.4.1
12
- pydocstyle==6.3.0
13
-
14
- [dev-formatting]
15
- black==24.4.2
16
- isort==5.13.2
17
-
18
- [dev-mkdocs]
19
- black==24.4.2
20
- Markdown==3.6
21
- mike==2.0.0
22
- mkdocs-gen-files==0.5.0
23
- mkdocs-literate-nav==0.6.1
24
- mkdocs-macros-plugin==1.0.5
25
- mkdocs-material==9.5.20
26
- mkdocstrings[python]==0.25.0
27
- frequenz-repo-config[lib]==0.9.1
28
-
29
- [dev-mypy]
30
- mypy==1.10.0
31
- types-Markdown==3.6.0.20240316
32
- frequenz-client-common[dev-mkdocs,dev-noxfile,dev-pytest]
33
-
34
- [dev-noxfile]
35
- nox==2024.4.15
36
- frequenz-repo-config[lib]==0.9.1
37
-
38
- [dev-pylint]
39
- pylint==3.1.0
40
- frequenz-client-common[dev-mkdocs,dev-noxfile,dev-pytest]
41
-
42
- [dev-pytest]
43
- pytest==8.2.0
44
- frequenz-repo-config[extra-lint-examples]==0.9.1
45
- pytest-mock==3.14.0
46
- pytest-asyncio==0.23.6
47
- async-solipsism==0.6