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.
- fluvius_energy_api/__init__.py +140 -0
- fluvius_energy_api/_http.py +128 -0
- fluvius_energy_api/auth.py +239 -0
- fluvius_energy_api/client.py +334 -0
- fluvius_energy_api/credentials.py +215 -0
- fluvius_energy_api/exceptions.py +104 -0
- fluvius_energy_api/models/__init__.py +123 -0
- fluvius_energy_api/models/base.py +36 -0
- fluvius_energy_api/models/energy.py +201 -0
- fluvius_energy_api/models/enums.py +137 -0
- fluvius_energy_api/models/installation.py +68 -0
- fluvius_energy_api/models/mandate.py +73 -0
- fluvius_energy_api/models/session.py +46 -0
- fluvius_energy_api/py.typed +0 -0
- fluvius_energy_api-0.1.0.dist-info/METADATA +311 -0
- fluvius_energy_api-0.1.0.dist-info/RECORD +18 -0
- fluvius_energy_api-0.1.0.dist-info/WHEEL +4 -0
- fluvius_energy_api-0.1.0.dist-info/licenses/LICENSE +661 -0
|
@@ -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,,
|