leneda-client 0.3.0__tar.gz → 0.4.0__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 (23) hide show
  1. {leneda_client-0.3.0/src/leneda_client.egg-info → leneda_client-0.4.0}/PKG-INFO +1 -1
  2. {leneda_client-0.3.0 → leneda_client-0.4.0}/src/leneda/client.py +44 -16
  3. {leneda_client-0.3.0 → leneda_client-0.4.0}/src/leneda/exceptions.py +0 -6
  4. {leneda_client-0.3.0 → leneda_client-0.4.0}/src/leneda/version.py +1 -1
  5. {leneda_client-0.3.0 → leneda_client-0.4.0/src/leneda_client.egg-info}/PKG-INFO +1 -1
  6. {leneda_client-0.3.0 → leneda_client-0.4.0}/tests/test_client.py +68 -11
  7. {leneda_client-0.3.0 → leneda_client-0.4.0}/LICENSE +0 -0
  8. {leneda_client-0.3.0 → leneda_client-0.4.0}/MANIFEST.in +0 -0
  9. {leneda_client-0.3.0 → leneda_client-0.4.0}/README.md +0 -0
  10. {leneda_client-0.3.0 → leneda_client-0.4.0}/examples/advanced_usage.py +0 -0
  11. {leneda_client-0.3.0 → leneda_client-0.4.0}/examples/basic_usage.py +0 -0
  12. {leneda_client-0.3.0 → leneda_client-0.4.0}/pyproject.toml +0 -0
  13. {leneda_client-0.3.0 → leneda_client-0.4.0}/requirements.txt +0 -0
  14. {leneda_client-0.3.0 → leneda_client-0.4.0}/setup.cfg +0 -0
  15. {leneda_client-0.3.0 → leneda_client-0.4.0}/setup.py +0 -0
  16. {leneda_client-0.3.0 → leneda_client-0.4.0}/src/leneda/__init__.py +0 -0
  17. {leneda_client-0.3.0 → leneda_client-0.4.0}/src/leneda/models.py +0 -0
  18. {leneda_client-0.3.0 → leneda_client-0.4.0}/src/leneda/obis_codes.py +0 -0
  19. {leneda_client-0.3.0 → leneda_client-0.4.0}/src/leneda_client.egg-info/SOURCES.txt +0 -0
  20. {leneda_client-0.3.0 → leneda_client-0.4.0}/src/leneda_client.egg-info/dependency_links.txt +0 -0
  21. {leneda_client-0.3.0 → leneda_client-0.4.0}/src/leneda_client.egg-info/requires.txt +0 -0
  22. {leneda_client-0.3.0 → leneda_client-0.4.0}/src/leneda_client.egg-info/top_level.txt +0 -0
  23. {leneda_client-0.3.0 → leneda_client-0.4.0}/tests/__init__.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: leneda-client
3
- Version: 0.3.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
@@ -12,7 +12,7 @@ from typing import Any, Dict, List, Optional, Union
12
12
 
13
13
  import requests
14
14
 
15
- from .exceptions import ForbiddenException, InvalidMeteringPointException, UnauthorizedException
15
+ from .exceptions import ForbiddenException, UnauthorizedException
16
16
  from .models import (
17
17
  AggregatedMeteringData,
18
18
  MeteringData,
@@ -250,19 +250,24 @@ class LenedaClient:
250
250
 
251
251
  return response_data
252
252
 
253
- def test_metering_point(self, metering_point_code: str) -> bool:
253
+ def probe_metering_point_obis_code(self, metering_point_code: str, obis_code: ObisCode) -> bool:
254
254
  """
255
- Test if a metering point code is valid and accessible.
255
+ Probe if a metering point provides data for a specific OBIS code.
256
256
 
257
- This method checks if a metering point code is valid by making a request
258
- for aggregated metering data. If the unit property in the response is null,
259
- it indicates that the metering point is invalid or not accessible.
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
260
264
 
261
265
  Args:
262
- metering_point_code: The metering point code to test
266
+ metering_point_code: The metering point code to probe
267
+ obis_code: The OBIS code to check for data availability
263
268
 
264
269
  Returns:
265
- bool: True if the metering point is valid and accessible, False otherwise
270
+ bool: True if the metering point provides data for the specified OBIS code, False otherwise
266
271
 
267
272
  Raises:
268
273
  UnauthorizedException: If the API returns a 401 status code
@@ -273,20 +278,43 @@ class LenedaClient:
273
278
  end_date = datetime.now()
274
279
  start_date = end_date - timedelta(weeks=4)
275
280
 
276
- # Try to get aggregated data for electricity consumption
281
+ # Try to get aggregated data for the specified OBIS code
277
282
  result = self.get_aggregated_metering_data(
278
283
  metering_point_code=metering_point_code,
279
- obis_code=ObisCode.ELEC_CONSUMPTION_ACTIVE,
284
+ obis_code=obis_code,
280
285
  start_date=start_date,
281
286
  end_date=end_date,
282
287
  aggregation_level="Month",
283
288
  transformation_mode="Accumulation",
284
289
  )
285
290
 
286
- # If we get here and the unit is None, the metering point is invalid
287
- if result.unit is None:
288
- raise InvalidMeteringPointException(
289
- f"Metering point {metering_point_code} is invalid or not accessible"
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
291
307
 
292
- return True
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
+ ]
@@ -19,9 +19,3 @@ class ForbiddenException(LenedaException):
19
19
  """Raised when access is forbidden (403 Forbidden), typically due to geoblocking or other access restrictions."""
20
20
 
21
21
  pass
22
-
23
-
24
- class InvalidMeteringPointException(LenedaException):
25
- """Raised when a metering point code is invalid or not accessible."""
26
-
27
- pass
@@ -1,3 +1,3 @@
1
1
  """Version information."""
2
2
 
3
- __version__ = "0.3.0"
3
+ __version__ = "0.4.0"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: leneda-client
3
- Version: 0.3.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
@@ -16,7 +16,6 @@ sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "..")
16
16
  from src.leneda import LenedaClient
17
17
  from src.leneda.exceptions import (
18
18
  ForbiddenException,
19
- InvalidMeteringPointException,
20
19
  UnauthorizedException,
21
20
  )
22
21
  from src.leneda.models import (
@@ -283,8 +282,8 @@ class TestLenedaClient(unittest.TestCase):
283
282
  )
284
283
 
285
284
  @patch("requests.request")
286
- def test_test_metering_point_valid(self, mock_request):
287
- """Test test_metering_point with a valid metering point."""
285
+ def test_probe_metering_point_obis_code_valid(self, mock_request):
286
+ """Test probe_metering_point_obis_code with a valid metering point and OBIS code."""
288
287
  # Set up the mock response with valid data
289
288
  mock_response = MagicMock()
290
289
  mock_response.status_code = 200
@@ -293,7 +292,9 @@ class TestLenedaClient(unittest.TestCase):
293
292
  mock_request.return_value = mock_response
294
293
 
295
294
  # Call the method
296
- result = self.client.test_metering_point("LU-METERING_POINT1")
295
+ result = self.client.probe_metering_point_obis_code(
296
+ "LU-METERING_POINT1", ObisCode.ELEC_CONSUMPTION_ACTIVE
297
+ )
297
298
 
298
299
  # Check the result
299
300
  self.assertTrue(result)
@@ -302,8 +303,8 @@ class TestLenedaClient(unittest.TestCase):
302
303
  mock_request.assert_called_once()
303
304
 
304
305
  @patch("requests.request")
305
- def test_test_metering_point_invalid(self, mock_request):
306
- """Test test_metering_point with an invalid metering point."""
306
+ def test_probe_metering_point_obis_code_invalid(self, mock_request):
307
+ """Test probe_metering_point_obis_code with an invalid metering point or unsupported OBIS code."""
307
308
  # Set up the mock response with null unit
308
309
  mock_response = MagicMock()
309
310
  mock_response.status_code = 200
@@ -311,16 +312,72 @@ class TestLenedaClient(unittest.TestCase):
311
312
  mock_response.content = json.dumps(mock_response.json.return_value).encode()
312
313
  mock_request.return_value = mock_response
313
314
 
314
- # Call the method and check that it raises InvalidMeteringPointException
315
- with self.assertRaises(InvalidMeteringPointException) as context:
316
- self.client.test_metering_point("INVALID-METERING-POINT")
315
+ # Call the method
316
+ result = self.client.probe_metering_point_obis_code(
317
+ "INVALID-METERING-POINT", ObisCode.ELEC_CONSUMPTION_ACTIVE
318
+ )
317
319
 
318
- # Check the error message
319
- self.assertIn("INVALID-METERING-POINT", str(context.exception))
320
+ # Check the result
321
+ self.assertFalse(result)
320
322
 
321
323
  # Check that the request was made correctly
322
324
  mock_request.assert_called_once()
323
325
 
326
+ @patch("requests.request")
327
+ def test_get_supported_obis_codes(self, mock_request):
328
+ """Test getting supported OBIS codes for a metering point."""
329
+
330
+ # Set up the mock response to return different results for different OBIS codes
331
+ def mock_response_side_effect(*args, **kwargs):
332
+ mock_response = MagicMock()
333
+ mock_response.status_code = 200
334
+
335
+ # Check which OBIS code is being probed
336
+ obis_code = kwargs.get("params", {}).get("obisCode")
337
+ if obis_code == ObisCode.ELEC_CONSUMPTION_ACTIVE.value:
338
+ mock_response.json.return_value = {"unit": "kWh", "aggregatedTimeSeries": []}
339
+ elif obis_code == ObisCode.ELEC_PRODUCTION_ACTIVE.value:
340
+ mock_response.json.return_value = {"unit": "kWh", "aggregatedTimeSeries": []}
341
+ else:
342
+ mock_response.json.return_value = {"unit": None, "aggregatedTimeSeries": []}
343
+
344
+ mock_response.content = json.dumps(mock_response.json.return_value).encode()
345
+ return mock_response
346
+
347
+ mock_request.side_effect = mock_response_side_effect
348
+
349
+ # Call the method
350
+ result = self.client.get_supported_obis_codes("LU-METERING_POINT1")
351
+
352
+ # Check the result
353
+ self.assertIsInstance(result, list)
354
+ self.assertEqual(len(result), 2) # We expect 2 supported OBIS codes
355
+ self.assertIn(ObisCode.ELEC_CONSUMPTION_ACTIVE, result)
356
+ self.assertIn(ObisCode.ELEC_PRODUCTION_ACTIVE, result)
357
+
358
+ # Check that the request was made for each OBIS code
359
+ self.assertEqual(mock_request.call_count, len(ObisCode))
360
+
361
+ @patch("requests.request")
362
+ def test_get_supported_obis_codes_none(self, mock_request):
363
+ """Test getting supported OBIS codes when none are supported."""
364
+ # Set up the mock response to return null unit for all OBIS codes
365
+ mock_response = MagicMock()
366
+ mock_response.status_code = 200
367
+ mock_response.json.return_value = {"unit": None, "aggregatedTimeSeries": []}
368
+ mock_response.content = json.dumps(mock_response.json.return_value).encode()
369
+ mock_request.return_value = mock_response
370
+
371
+ # Call the method
372
+ result = self.client.get_supported_obis_codes("INVALID-METERING-POINT")
373
+
374
+ # Check the result
375
+ self.assertIsInstance(result, list)
376
+ self.assertEqual(len(result), 0) # No supported OBIS codes
377
+
378
+ # Check that the request was made for each OBIS code
379
+ self.assertEqual(mock_request.call_count, len(ObisCode))
380
+
324
381
 
325
382
  if __name__ == "__main__":
326
383
  unittest.main()
File without changes
File without changes
File without changes
File without changes
File without changes