leneda-client 0.2.0__py3-none-any.whl → 0.4.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.
- leneda/client.py +85 -1
- leneda/exceptions.py +21 -0
- leneda/version.py +1 -1
- {leneda_client-0.2.0.dist-info → leneda_client-0.4.0.dist-info}/METADATA +37 -4
- leneda_client-0.4.0.dist-info/RECORD +11 -0
- {leneda_client-0.2.0.dist-info → leneda_client-0.4.0.dist-info}/WHEEL +1 -1
- leneda_client-0.4.0.dist-info/licenses/LICENSE +21 -0
- leneda_client-0.2.0.dist-info/RECORD +0 -9
- {leneda_client-0.2.0.dist-info → leneda_client-0.4.0.dist-info}/top_level.txt +0 -0
leneda/client.py
CHANGED
@@ -7,11 +7,12 @@ energy consumption and production data for electricity and gas.
|
|
7
7
|
|
8
8
|
import json
|
9
9
|
import logging
|
10
|
-
from datetime import datetime
|
10
|
+
from datetime import datetime, timedelta
|
11
11
|
from typing import Any, Dict, List, Optional, Union
|
12
12
|
|
13
13
|
import requests
|
14
14
|
|
15
|
+
from .exceptions import ForbiddenException, UnauthorizedException
|
15
16
|
from .models import (
|
16
17
|
AggregatedMeteringData,
|
17
18
|
MeteringData,
|
@@ -70,6 +71,12 @@ class LenedaClient:
|
|
70
71
|
|
71
72
|
Returns:
|
72
73
|
The JSON response from the API
|
74
|
+
|
75
|
+
Raises:
|
76
|
+
UnauthorizedException: If the API returns a 401 status code
|
77
|
+
ForbiddenException: If the API returns a 403 status code
|
78
|
+
requests.exceptions.RequestException: For other request errors
|
79
|
+
json.JSONDecodeError: If the response cannot be parsed as JSON
|
73
80
|
"""
|
74
81
|
url = f"{self.BASE_URL}/{endpoint}"
|
75
82
|
|
@@ -87,6 +94,14 @@ class LenedaClient:
|
|
87
94
|
)
|
88
95
|
|
89
96
|
# Check for HTTP errors
|
97
|
+
if response.status_code == 401:
|
98
|
+
raise UnauthorizedException(
|
99
|
+
"API authentication failed. Please check your API key and energy ID."
|
100
|
+
)
|
101
|
+
if response.status_code == 403:
|
102
|
+
raise ForbiddenException(
|
103
|
+
"Access forbidden. This may be due to Leneda's geoblocking or other access restrictions."
|
104
|
+
)
|
90
105
|
response.raise_for_status()
|
91
106
|
|
92
107
|
# Parse the response
|
@@ -234,3 +249,72 @@ class LenedaClient:
|
|
234
249
|
response_data = self._make_request(method="POST", endpoint=endpoint, json_data=data)
|
235
250
|
|
236
251
|
return response_data
|
252
|
+
|
253
|
+
def probe_metering_point_obis_code(self, metering_point_code: str, obis_code: ObisCode) -> bool:
|
254
|
+
"""
|
255
|
+
Probe if a metering point provides data for a specific OBIS code.
|
256
|
+
|
257
|
+
NOTE: This method is essentially a best guess since the Leneda API does not provide a way to check
|
258
|
+
if a metering point provides data for a specific OBIS code or whether a metering point code is valid
|
259
|
+
|
260
|
+
This method checks if a metering point provides data for the specified OBIS code by making a request
|
261
|
+
for aggregated metering data. If the unit property in the response is null, it indicates that either:
|
262
|
+
- The metering point is invalid, or
|
263
|
+
- The metering point does not provide data for the specified OBIS code
|
264
|
+
|
265
|
+
Args:
|
266
|
+
metering_point_code: The metering point code to probe
|
267
|
+
obis_code: The OBIS code to check for data availability
|
268
|
+
|
269
|
+
Returns:
|
270
|
+
bool: True if the metering point provides data for the specified OBIS code, False otherwise
|
271
|
+
|
272
|
+
Raises:
|
273
|
+
UnauthorizedException: If the API returns a 401 status code
|
274
|
+
ForbiddenException: If the API returns a 403 status code
|
275
|
+
requests.exceptions.RequestException: For other request errors
|
276
|
+
"""
|
277
|
+
# Use arbitrary time window
|
278
|
+
end_date = datetime.now()
|
279
|
+
start_date = end_date - timedelta(weeks=4)
|
280
|
+
|
281
|
+
# Try to get aggregated data for the specified OBIS code
|
282
|
+
result = self.get_aggregated_metering_data(
|
283
|
+
metering_point_code=metering_point_code,
|
284
|
+
obis_code=obis_code,
|
285
|
+
start_date=start_date,
|
286
|
+
end_date=end_date,
|
287
|
+
aggregation_level="Month",
|
288
|
+
transformation_mode="Accumulation",
|
289
|
+
)
|
290
|
+
|
291
|
+
# Return True if we got data (unit is not None), False otherwise
|
292
|
+
return result.unit is not None
|
293
|
+
|
294
|
+
def get_supported_obis_codes(self, metering_point_code: str) -> List[ObisCode]:
|
295
|
+
"""
|
296
|
+
Get all OBIS codes that are supported by a given metering point.
|
297
|
+
|
298
|
+
NOTE: Please see the documentation of the probe_metering_point_obis_code method about best guess
|
299
|
+
behaviour. If this method returns an empty list, chances are high that the metering point code
|
300
|
+
is invalid or that the Energy ID has no access to it.
|
301
|
+
|
302
|
+
This method probes each OBIS code defined in the ObisCode enum to determine
|
303
|
+
which ones are supported by the specified metering point.
|
304
|
+
|
305
|
+
Args:
|
306
|
+
metering_point_code: The metering point code to check
|
307
|
+
|
308
|
+
Returns:
|
309
|
+
List[ObisCode]: A list of OBIS codes that are supported by the metering point
|
310
|
+
|
311
|
+
Raises:
|
312
|
+
UnauthorizedException: If the API returns a 401 status code
|
313
|
+
ForbiddenException: If the API returns a 403 status code
|
314
|
+
requests.exceptions.RequestException: For other request errors
|
315
|
+
"""
|
316
|
+
return [
|
317
|
+
obis_code
|
318
|
+
for obis_code in ObisCode
|
319
|
+
if self.probe_metering_point_obis_code(metering_point_code, obis_code)
|
320
|
+
]
|
leneda/exceptions.py
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
"""
|
2
|
+
Custom exceptions for the Leneda API client.
|
3
|
+
"""
|
4
|
+
|
5
|
+
|
6
|
+
class LenedaException(Exception):
|
7
|
+
"""Base exception for all Leneda API client exceptions."""
|
8
|
+
|
9
|
+
pass
|
10
|
+
|
11
|
+
|
12
|
+
class UnauthorizedException(LenedaException):
|
13
|
+
"""Raised when API authentication fails (401 Unauthorized)."""
|
14
|
+
|
15
|
+
pass
|
16
|
+
|
17
|
+
|
18
|
+
class ForbiddenException(LenedaException):
|
19
|
+
"""Raised when access is forbidden (403 Forbidden), typically due to geoblocking or other access restrictions."""
|
20
|
+
|
21
|
+
pass
|
leneda/version.py
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: leneda-client
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.4.0
|
4
4
|
Summary: Python client for the Leneda energy data platform
|
5
5
|
Home-page: https://github.com/fedus/leneda-client
|
6
6
|
Author: fedus
|
@@ -21,6 +21,7 @@ Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
21
21
|
Classifier: Topic :: Utilities
|
22
22
|
Requires-Python: >=3.8
|
23
23
|
Description-Content-Type: text/markdown
|
24
|
+
License-File: LICENSE
|
24
25
|
Requires-Dist: requests>=2.25.0
|
25
26
|
Requires-Dist: python-dateutil>=2.8.2
|
26
27
|
Dynamic: author
|
@@ -30,6 +31,7 @@ Dynamic: description
|
|
30
31
|
Dynamic: description-content-type
|
31
32
|
Dynamic: home-page
|
32
33
|
Dynamic: keywords
|
34
|
+
Dynamic: license-file
|
33
35
|
Dynamic: project-url
|
34
36
|
Dynamic: requires-dist
|
35
37
|
Dynamic: requires-python
|
@@ -37,9 +39,10 @@ Dynamic: summary
|
|
37
39
|
|
38
40
|
# Leneda API Client
|
39
41
|
|
40
|
-
[![PyPI version]](https://pypi.org/project/leneda-client/)
|
41
|
-
[![Python
|
42
|
-
[![License]](https://github.com/fedus/leneda-client/blob/main/LICENSE)
|
42
|
+
[](https://pypi.org/project/leneda-client/)
|
43
|
+
[](https://pypi.org/project/leneda-client/)
|
44
|
+
[](https://github.com/fedus/leneda-client/blob/main/LICENSE)
|
45
|
+
|
43
46
|
|
44
47
|
A Python client for interacting with the Leneda energy data platform API.
|
45
48
|
|
@@ -56,3 +59,33 @@ This client provides a simple interface to the Leneda API, which allows users to
|
|
56
59
|
|
57
60
|
```bash
|
58
61
|
pip install leneda-client
|
62
|
+
```
|
63
|
+
|
64
|
+
## Trying it out
|
65
|
+
|
66
|
+
```bash
|
67
|
+
$ export LENEDA_ENERGY_ID='LUXE-xx-yy-1234'
|
68
|
+
$ export LENEDA_API_KEY='YOUR-API-KEY'
|
69
|
+
$ python examples/basic_usage.py --metering-point LU0000012345678901234000000000000
|
70
|
+
Example 1: Getting hourly electricity consumption data for the last 7 days
|
71
|
+
Retrieved 514 consumption measurements
|
72
|
+
Unit: kW
|
73
|
+
Interval length: PT15M
|
74
|
+
Metering point: LU0000012345678901234000000000000
|
75
|
+
OBIS code: ObisCode.ELEC_CONSUMPTION_ACTIVE
|
76
|
+
|
77
|
+
First 3 measurements:
|
78
|
+
Time: 2025-04-18T13:30:00+00:00, Value: 0.048 kW, Type: Actual, Version: 2, Calculated: False
|
79
|
+
Time: 2025-04-18T13:45:00+00:00, Value: 0.08 kW, Type: Actual, Version: 2, Calculated: False
|
80
|
+
Time: 2025-04-18T14:00:00+00:00, Value: 0.08 kW, Type: Actual, Version: 2, Calculated: False
|
81
|
+
|
82
|
+
Example 2: Getting monthly aggregated electricity consumption for 2025
|
83
|
+
Retrieved 4 monthly aggregations
|
84
|
+
Unit: kWh
|
85
|
+
|
86
|
+
Monthly consumption:
|
87
|
+
Period: 2024-12 to 2025-01, Value: 30.858 kWh, Calculated: False
|
88
|
+
Period: 2025-01 to 2025-02, Value: 148.985 kWh, Calculated: False
|
89
|
+
Period: 2025-02 to 2025-03, Value: 44.619 kWh, Calculated: False
|
90
|
+
Period: 2025-03 to 2025-04, Value: 29.662 kWh, Calculated: False
|
91
|
+
```
|
@@ -0,0 +1,11 @@
|
|
1
|
+
leneda/__init__.py,sha256=-BHIXBfTTbX6EKDHr2Bq7rPzsPNYrrkgs9AJqWJR_1Q,732
|
2
|
+
leneda/client.py,sha256=RcANz6UweQ13fJHKwWP1V5dWnqSwcG4Ot9ws1grhZqQ,12250
|
3
|
+
leneda/exceptions.py,sha256=q00gjI5VwXAMF2I1gXfQidZMzbCF6UOSo4i1Wnb-inU,460
|
4
|
+
leneda/models.py,sha256=jdU2cIZZDExUSiSfz9zaYjJepr0m3v_x5b1fyOaEI8Q,7930
|
5
|
+
leneda/obis_codes.py,sha256=VfsJQN1U80eZ5g1bIteDCLkkmBQ0AIkkm_zNAeM1Dog,7507
|
6
|
+
leneda/version.py,sha256=e6aGg4sxTYiyshAbW98gDoekO-J6qYKpZNzhVZhaYUk,50
|
7
|
+
leneda_client-0.4.0.dist-info/licenses/LICENSE,sha256=nAhDs625lK6v8oLqjWCABKBKlwxVoRDFXQvoZPfOtKQ,1062
|
8
|
+
leneda_client-0.4.0.dist-info/METADATA,sha256=TGPWdTziOm6yt9HLE8GKtbDxUaU-N9GHcNH9vsAbdzw,3344
|
9
|
+
leneda_client-0.4.0.dist-info/WHEEL,sha256=0CuiUZ_p9E4cD6NyLD6UG80LBXYyiSYZOKDm5lp32xk,91
|
10
|
+
leneda_client-0.4.0.dist-info/top_level.txt,sha256=PANScm25ep7WLjKiph0fhJPb8s_sa_uLHemnBpQBaJ8,7
|
11
|
+
leneda_client-0.4.0.dist-info/RECORD,,
|
@@ -0,0 +1,21 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2025 fedus
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
@@ -1,9 +0,0 @@
|
|
1
|
-
leneda/__init__.py,sha256=-BHIXBfTTbX6EKDHr2Bq7rPzsPNYrrkgs9AJqWJR_1Q,732
|
2
|
-
leneda/client.py,sha256=NFZczkNkvTBZOSU5FCQ9A_TE_x4s7eX9iKrWqzeubr4,8393
|
3
|
-
leneda/models.py,sha256=jdU2cIZZDExUSiSfz9zaYjJepr0m3v_x5b1fyOaEI8Q,7930
|
4
|
-
leneda/obis_codes.py,sha256=VfsJQN1U80eZ5g1bIteDCLkkmBQ0AIkkm_zNAeM1Dog,7507
|
5
|
-
leneda/version.py,sha256=K2uqgpmNuApS_OV5kcSoshVG9LFQlr-es1HuZALwCq4,50
|
6
|
-
leneda_client-0.2.0.dist-info/METADATA,sha256=CqBEdkRXJUCOk9qSKmv9ZBNIgzov_9mroXa5v7i_pcA,1994
|
7
|
-
leneda_client-0.2.0.dist-info/WHEEL,sha256=lTU6B6eIfYoiQJTZNc-fyaR6BpL6ehTzU3xGYxn2n8k,91
|
8
|
-
leneda_client-0.2.0.dist-info/top_level.txt,sha256=PANScm25ep7WLjKiph0fhJPb8s_sa_uLHemnBpQBaJ8,7
|
9
|
-
leneda_client-0.2.0.dist-info/RECORD,,
|
File without changes
|