fluvius-energy-api 0.1.0__py3-none-any.whl

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.
@@ -0,0 +1,311 @@
1
+ Metadata-Version: 2.4
2
+ Name: fluvius-energy-api
3
+ Version: 0.1.0
4
+ Summary: Python wrapper for the Fluvius Energy API
5
+ Project-URL: Homepage, https://github.com/warreee/fluvius-energy-api
6
+ Project-URL: Repository, https://github.com/warreee/fluvius-energy-api.git
7
+ Project-URL: Issues, https://github.com/warreee/fluvius-energy-api/issues
8
+ Author: Ward Schodts
9
+ License-Expression: AGPL-3.0-or-later
10
+ License-File: LICENSE
11
+ Keywords: api,belgium,electricity,energy,esco,fluvius,gas,smart-meter
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: GNU Affero General Public License v3 or later (AGPLv3+)
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.13
18
+ Classifier: Topic :: Home Automation
19
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
20
+ Classifier: Typing :: Typed
21
+ Requires-Python: >=3.13
22
+ Requires-Dist: cryptography>=43.0.0
23
+ Requires-Dist: httpx>=0.27.0
24
+ Requires-Dist: pydantic>=2.0.0
25
+ Requires-Dist: pyjwt>=2.8.0
26
+ Description-Content-Type: text/markdown
27
+
28
+ # Fluvius Energy API
29
+
30
+ Python wrapper for the Fluvius Energy API v3 (ESCO - Energy Service Company API).
31
+
32
+ ## Installation
33
+
34
+ ```bash
35
+ pip install fluvius-energy-api
36
+ ```
37
+
38
+ Or with uv:
39
+
40
+ ```bash
41
+ uv add fluvius-energy-api
42
+ ```
43
+
44
+ ## Configuration
45
+
46
+ The client requires OAuth2 credentials for Azure AD authentication. Two authentication methods are supported:
47
+
48
+ - **Certificate-based** (production): Uses certificate thumbprint + private key
49
+ - **Client secret** (sandbox): Uses a simple client secret
50
+
51
+ ### Common Environment Variables
52
+
53
+ These are shared between production and sandbox:
54
+
55
+ | Variable | Description |
56
+ |----------|-------------|
57
+ | `FLUVIUS_SUBSCRIPTION_KEY` | Azure API Management subscription key |
58
+ | `FLUVIUS_CLIENT_ID` | Azure AD application (client) ID |
59
+ | `FLUVIUS_TENANT_ID` | Azure AD tenant ID |
60
+ | `FLUVIUS_SCOPE` | OAuth2 scope (e.g., `api://dcfd07b1-f05e-4005-a6fb-7929be1bece4/.default`) |
61
+
62
+ ### Production (Certificate-based auth)
63
+
64
+ | Variable | Description |
65
+ |----------|-------------|
66
+ | `FLUVIUS_CERTIFICATE_THUMBPRINT` | Certificate thumbprint (hex format) |
67
+ | `FLUVIUS_PRIVATE_KEY` | RSA private key in PEM format |
68
+ | `FLUVIUS_PRIVATE_KEY_PATH` | Alternative: path to private key file |
69
+
70
+ ### Sandbox (Client secret auth)
71
+
72
+ | Variable | Description |
73
+ |----------|-------------|
74
+ | `FLUVIUS_SANDBOX_CLIENT_SECRET` | Client secret for sandbox |
75
+
76
+ Note: For sandbox, common values (subscription_key, client_id, tenant_id, scope, data_access_contract_number) automatically fall back to `FLUVIUS_*` if not set with `FLUVIUS_SANDBOX_*` prefix.
77
+
78
+ ### Data Access Contract
79
+
80
+ | Variable | Description |
81
+ |----------|-------------|
82
+ | `FLUVIUS_DATA_ACCESS_CONTRACT_NUMBER` | Data access contract number (required, typically constant per service provider) |
83
+
84
+ ### Private Key Formats
85
+
86
+ The private key can be provided in three ways:
87
+ 1. **Inline PEM**: Set `FLUVIUS_PRIVATE_KEY` with the full PEM content
88
+ 2. **Base64-encoded**: Set `FLUVIUS_PRIVATE_KEY` with the PEM content encoded as base64
89
+ 3. **File path**: Set `FLUVIUS_PRIVATE_KEY_PATH` to point to a `.pem` file
90
+
91
+ ## Usage
92
+
93
+ ### Production (Certificate auth)
94
+
95
+ ```python
96
+ from fluvius_energy_api import FluviusEnergyClient, Environment
97
+
98
+ # Credentials loaded from FLUVIUS_* environment variables
99
+ with FluviusEnergyClient(environment=Environment.PRODUCTION) as client:
100
+ response = client.get_mandates()
101
+ for mandate in response.data.mandates:
102
+ print(f"EAN: {mandate.ean}, Status: {mandate.status}")
103
+ ```
104
+
105
+ ### Sandbox (Client secret auth)
106
+
107
+ ```python
108
+ from fluvius_energy_api import FluviusEnergyClient, FluviusCredentials, Environment
109
+
110
+ # Load credentials - falls back to FLUVIUS_* for common values,
111
+ # uses FLUVIUS_SANDBOX_CLIENT_SECRET for auth
112
+ sandbox_credentials = FluviusCredentials.from_env(prefix="FLUVIUS_SANDBOX")
113
+
114
+ with FluviusEnergyClient(credentials=sandbox_credentials, environment=Environment.SANDBOX) as client:
115
+ response = client.get_mandates()
116
+ print(f"Found {len(response.data.mandates)} mandates in sandbox")
117
+ ```
118
+
119
+ ### Explicit Credentials
120
+
121
+ ```python
122
+ from fluvius_energy_api import FluviusEnergyClient, FluviusCredentials, Environment
123
+
124
+ # Production with certificate
125
+ prod_credentials = FluviusCredentials(
126
+ subscription_key="your-subscription-key",
127
+ client_id="your-client-id",
128
+ tenant_id="your-tenant-id",
129
+ scope="api://your-scope/.default",
130
+ certificate_thumbprint="YOUR_CERTIFICATE_THUMBPRINT",
131
+ private_key="-----BEGIN RSA PRIVATE KEY-----\n...\n-----END RSA PRIVATE KEY-----",
132
+ )
133
+
134
+ # Sandbox with client secret
135
+ sandbox_credentials = FluviusCredentials(
136
+ subscription_key="your-subscription-key",
137
+ client_id="your-client-id",
138
+ tenant_id="your-tenant-id",
139
+ scope="api://your-scope/.default",
140
+ client_secret="your-client-secret",
141
+ )
142
+
143
+ with FluviusEnergyClient(credentials=prod_credentials, environment=Environment.PRODUCTION) as client:
144
+ mandates = client.get_mandates()
145
+ ```
146
+
147
+ ### Create Client Session
148
+
149
+ Create a session for end-users to grant data access:
150
+
151
+ ```python
152
+ from fluvius_energy_api import (
153
+ FluviusEnergyClient,
154
+ ClientSessionDataService,
155
+ DataServiceType,
156
+ Environment,
157
+ )
158
+
159
+ with FluviusEnergyClient(environment=Environment.PRODUCTION) as client:
160
+ response = client.create_client_session(
161
+ data_access_contract_number="3599900040",
162
+ reference_number="my-unique-reference",
163
+ flow="B2B",
164
+ data_services=[
165
+ ClientSessionDataService(
166
+ data_service_type=DataServiceType.VH_DAG,
167
+ data_period_from="2024-01-01T00:00:00Z",
168
+ ),
169
+ ClientSessionDataService(
170
+ data_service_type=DataServiceType.VH_KWARTIER_UUR,
171
+ data_period_from="2024-01-01T00:00:00Z",
172
+ ),
173
+ ],
174
+ number_of_eans=5,
175
+ )
176
+
177
+ if response.data.status == "success":
178
+ # Build the consent URL for end-users
179
+ consent_url = f"https://mijn.fluvius.be/verbruik/dienstverlener?id={response.data.short_url_identifier}"
180
+ print(f"Consent URL: {consent_url}")
181
+ print(f"Valid until: {response.data.valid_to}")
182
+ ```
183
+
184
+ ### Get Mandates
185
+
186
+ Retrieve mandates with optional filters:
187
+
188
+ ```python
189
+ from fluvius_energy_api import (
190
+ FluviusEnergyClient,
191
+ EnergyType,
192
+ MandateStatus,
193
+ DataServiceType,
194
+ Environment,
195
+ )
196
+
197
+ with FluviusEnergyClient(environment=Environment.PRODUCTION) as client:
198
+ # Get all mandates
199
+ response = client.get_mandates()
200
+
201
+ # Get mandates with filters
202
+ response = client.get_mandates(
203
+ ean="541448800000004312",
204
+ energy_type=EnergyType.ELECTRICITY,
205
+ status=MandateStatus.APPROVED,
206
+ data_service_types=[DataServiceType.VH_DAG, DataServiceType.VH_KWARTIER_UUR],
207
+ )
208
+
209
+ for mandate in response.data.mandates:
210
+ print(f"EAN: {mandate.ean}")
211
+ print(f"Status: {mandate.status}")
212
+ print(f"Energy type: {mandate.energy_type}")
213
+ print(f"Data service: {mandate.data_service_type}")
214
+ ```
215
+
216
+ ### Get Energy Data
217
+
218
+ Retrieve energy consumption/production data:
219
+
220
+ ```python
221
+ from datetime import datetime
222
+ from fluvius_energy_api import FluviusEnergyClient, PeriodType, Environment
223
+
224
+ with FluviusEnergyClient(environment=Environment.PRODUCTION) as client:
225
+ response = client.get_energy(
226
+ ean="541448800000004312",
227
+ period_type=PeriodType.READ_TIME,
228
+ granularity="daily",
229
+ from_date=datetime(2024, 1, 1),
230
+ to_date=datetime(2024, 6, 1),
231
+ )
232
+
233
+ headpoint = response.data.headpoint
234
+ print(f"EAN: {headpoint.ean}")
235
+ print(f"Energy type: {headpoint.energy_type}")
236
+ ```
237
+
238
+ ## Environments
239
+
240
+ The client supports two environments:
241
+
242
+ | Environment | Base URL | Auth Method |
243
+ |-------------|----------|-------------|
244
+ | `Environment.PRODUCTION` | `https://apihub.fluvius.be/esco-live/v3` | Certificate |
245
+ | `Environment.SANDBOX` | `https://apihub.fluvius.be/esco-sbx/v3` | Client secret |
246
+
247
+ ```python
248
+ from fluvius_energy_api import FluviusEnergyClient, Environment
249
+
250
+ # Production
251
+ client = FluviusEnergyClient(environment=Environment.PRODUCTION)
252
+
253
+ # Sandbox
254
+ client = FluviusEnergyClient(environment=Environment.SANDBOX)
255
+ ```
256
+
257
+ ## Error Handling
258
+
259
+ The client raises specific exceptions for different error scenarios:
260
+
261
+ ```python
262
+ from fluvius_energy_api import (
263
+ FluviusEnergyClient,
264
+ FluviusAPIError,
265
+ AuthenticationError,
266
+ ForbiddenError,
267
+ NotFoundError,
268
+ ValidationError,
269
+ ServerError,
270
+ ServiceUnavailableError,
271
+ ConfigurationError,
272
+ Environment,
273
+ )
274
+
275
+ try:
276
+ with FluviusEnergyClient(environment=Environment.PRODUCTION) as client:
277
+ response = client.get_mandates()
278
+ except ConfigurationError as e:
279
+ print(f"Configuration error: {e}")
280
+ except AuthenticationError as e:
281
+ print(f"Authentication failed: {e}")
282
+ except ForbiddenError as e:
283
+ print(f"Access forbidden: {e}")
284
+ except NotFoundError as e:
285
+ print(f"Resource not found: {e}")
286
+ except ValidationError as e:
287
+ print(f"Validation error: {e}")
288
+ if e.validation_errors:
289
+ for error in e.validation_errors:
290
+ print(f" - {error}")
291
+ except ServerError as e:
292
+ print(f"Server error: {e}")
293
+ except ServiceUnavailableError as e:
294
+ print(f"Service unavailable: {e}")
295
+ except FluviusAPIError as e:
296
+ print(f"API error: {e}")
297
+ ```
298
+
299
+ ## Data Service Types
300
+
301
+ Available data service types:
302
+
303
+ | Type | Description |
304
+ |------|-------------|
305
+ | `VH_DAG` | Daily consumption history |
306
+ | `VH_KWARTIER_UUR` | Quarter-hourly/hourly consumption history |
307
+ | `VH_ONBEPAALD` | Indefinite consumption history |
308
+ | `IG` | Installation data |
309
+ ## License
310
+
311
+ GNU AFFERO GENERAL PUBLIC LICENSE
@@ -0,0 +1,18 @@
1
+ fluvius_energy_api/__init__.py,sha256=r9YmMlNy1FhWyd0HGR-iDanalwLTmGyXWHCFe-KcSgI,3459
2
+ fluvius_energy_api/_http.py,sha256=yt82D8aBKwpQBchScvFaPQvOPv8BVJN0Mgnvz6ROMDE,4331
3
+ fluvius_energy_api/auth.py,sha256=w9MKugj-xkSuBD37fCObx7FTT0CycM7ITHBaB4xsLgE,7667
4
+ fluvius_energy_api/client.py,sha256=E_yku_t3oQn-YgsQt0afKt5Lj3dCqgg5p9k4yi9FTGQ,12610
5
+ fluvius_energy_api/credentials.py,sha256=Z6Cy7WQxQJYRmpRlIsCS-cRfzEEvXk4F-RBmlup76PY,7746
6
+ fluvius_energy_api/exceptions.py,sha256=Z6Sb95eouiFl6Sc7YGcBuEH-apB4urVhfh26BgcAVQk,3387
7
+ fluvius_energy_api/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
+ fluvius_energy_api/models/__init__.py,sha256=20d6_vhmeNl_A4YC1afUYbpiwBB2oKbo7UFG8fHal3g,2917
9
+ fluvius_energy_api/models/base.py,sha256=n-bgJmbc7DhP7KLlUYDHjmvRg7GyLtFYGvz3_Cb3ZI4,1009
10
+ fluvius_energy_api/models/energy.py,sha256=Cl4D0mazS3DRqsb6wKTGIAN7f5ye_cAYaFnFf8pA7BA,6612
11
+ fluvius_energy_api/models/enums.py,sha256=Z2dDoi5Ac2uM1-nWkNqGTlfxCfOPxJrPIb-H0MLBM10,2891
12
+ fluvius_energy_api/models/installation.py,sha256=Akyz9IT6Z3ZB-wQpn-ZxSx82j7MMm6hVgEQgtDBtOUw,2274
13
+ fluvius_energy_api/models/mandate.py,sha256=Pd7Ju1XsppuGzudmeh9hguRWF-zwYR8nH3jY5NFGs-I,2578
14
+ fluvius_energy_api/models/session.py,sha256=wipa5U24zj9WTbxyKsgDHLqTC8tC3Twok1IdUMGt1WE,1922
15
+ fluvius_energy_api-0.1.0.dist-info/METADATA,sha256=uI-P5cJ2sbMh3gMQCh-yVIkJ_WzmABiklRvem3lGgMM,9646
16
+ fluvius_energy_api-0.1.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
17
+ fluvius_energy_api-0.1.0.dist-info/licenses/LICENSE,sha256=hIahDEOTzuHCU5J2nd07LWwkLW7Hko4UFO__ffsvB-8,34523
18
+ fluvius_energy_api-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.28.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any