e-data 1.2.17__tar.gz → 1.2.18__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 (27) hide show
  1. e-data-1.2.18/PKG-INFO +128 -0
  2. e-data-1.2.18/e_data.egg-info/PKG-INFO +128 -0
  3. {e-data-1.2.17 → e-data-1.2.18}/edata/connectors/datadis.py +73 -55
  4. {e-data-1.2.17 → e-data-1.2.18}/edata/helpers.py +10 -8
  5. {e-data-1.2.17 → e-data-1.2.18}/setup.py +1 -1
  6. e-data-1.2.17/PKG-INFO +0 -128
  7. e-data-1.2.17/e_data.egg-info/PKG-INFO +0 -128
  8. {e-data-1.2.17 → e-data-1.2.18}/LICENSE +0 -0
  9. {e-data-1.2.17 → e-data-1.2.18}/MANIFEST.in +0 -0
  10. {e-data-1.2.17 → e-data-1.2.18}/README.md +0 -0
  11. {e-data-1.2.17 → e-data-1.2.18}/e_data.egg-info/SOURCES.txt +0 -0
  12. {e-data-1.2.17 → e-data-1.2.18}/e_data.egg-info/dependency_links.txt +0 -0
  13. {e-data-1.2.17 → e-data-1.2.18}/e_data.egg-info/requires.txt +0 -0
  14. {e-data-1.2.17 → e-data-1.2.18}/e_data.egg-info/top_level.txt +0 -0
  15. {e-data-1.2.17 → e-data-1.2.18}/edata/__init__.py +0 -0
  16. {e-data-1.2.17 → e-data-1.2.18}/edata/connectors/__init__.py +0 -0
  17. {e-data-1.2.17 → e-data-1.2.18}/edata/connectors/redata.py +0 -0
  18. {e-data-1.2.17 → e-data-1.2.18}/edata/const.py +0 -0
  19. {e-data-1.2.17 → e-data-1.2.18}/edata/definitions.py +0 -0
  20. {e-data-1.2.17 → e-data-1.2.18}/edata/processors/__init__.py +0 -0
  21. {e-data-1.2.17 → e-data-1.2.18}/edata/processors/base.py +0 -0
  22. {e-data-1.2.17 → e-data-1.2.18}/edata/processors/billing.py +0 -0
  23. {e-data-1.2.17 → e-data-1.2.18}/edata/processors/consumption.py +0 -0
  24. {e-data-1.2.17 → e-data-1.2.18}/edata/processors/maximeter.py +0 -0
  25. {e-data-1.2.17 → e-data-1.2.18}/edata/processors/utils.py +0 -0
  26. {e-data-1.2.17 → e-data-1.2.18}/edata/storage.py +0 -0
  27. {e-data-1.2.17 → e-data-1.2.18}/setup.cfg +0 -0
e-data-1.2.18/PKG-INFO ADDED
@@ -0,0 +1,128 @@
1
+ Metadata-Version: 2.1
2
+ Name: e-data
3
+ Version: 1.2.18
4
+ Summary: Python library for managing spanish energy data from various web providers
5
+ Home-page: https://github.com/uvejota/python-edata
6
+ Author: VMG
7
+ Author-email: vmayorg@outlook.es
8
+ License: GPLv3
9
+ Description:
10
+ [![Downloads](https://pepy.tech/badge/e-data)](https://pepy.tech/project/e-data)
11
+ [![Downloads](https://pepy.tech/badge/e-data/month)](https://pepy.tech/project/e-data)
12
+ [![Downloads](https://pepy.tech/badge/e-data/week)](https://pepy.tech/project/e-data)
13
+
14
+ # python-edata
15
+
16
+ Este paquete proporciona herramientas para la descarga de tus datos de consumo eléctrico (desde Datadis.es) y su posterior procesado. La motivación principal es que conocer el consumo puede ayudarnos a reducirlo, e incluso a elegir una tarifa que mejor se adapte a nuestras necesidades. A día de hoy sus capacidades de facturación (€) son limitadas, soporta PVPC (según disponibilidad de datos de REData) y tarificación fija por tramos. Es el corazón de la integración [homeassistant-edata](https://github.com/uvejota/homeassistant-edata).
17
+
18
+ _**Esta herramienta no mantiene ningún tipo de vinculación con los proveedores de datos anteriormente mencionados, simplemente consulta la información disponible y facilita su posterior análisis.**_
19
+
20
+ ## Instalación
21
+
22
+ Puedes instalar la última versión estable mediante:
23
+
24
+ ``` bash
25
+ pip install e-data
26
+ ```
27
+
28
+ Si quieres probar la versión `dev` o contribuir a su desarrollo, clona este repositorio e instala manualmente las dependencias:
29
+
30
+ ``` bash
31
+ pip install -r requirements.txt
32
+ ```
33
+
34
+ ## Estructura
35
+
36
+ El paquete consta de tres módulos diferenciados:
37
+
38
+ * **Conectores** (módulo `connectors`), para definir los métodos de consulta a los diferentes proveedores: Datadis y REData.
39
+ * **Procesadores** (módulo `processors`), para procesar datos de consumo, maxímetro, o coste (tarificación). Ahora mismo consta de tres procesadores: `billing`, `consumption` y `maximeter`, además de algunas utilidades ubicadas en `utils`. Los procesadores deben heredar de la clase Processor definida en `base.py`
40
+ * **Ayudantes** (módulo `helpers`), para ayudar en el uso y gestión de los anteriores, presentando de momento un único ayudante llamado `EdataHelper` que te permite recopilar `X` días de datos (por defecto 365) y automáticamente procesarlos. Los datos son almacenados en la variable `data`, mientras que los atributos autocalculados son almacenados en la variable `attributes`. Por lo general, primero utilizan los conectores y luego procesan los datos, gestionando varias tareas de recuperación (principalmente para Datadis).
41
+
42
+ Estos módulos corresponden a la siguiente estructura del paquete:
43
+
44
+ ```
45
+ edata/
46
+ · __init__.py
47
+ · connectors/
48
+ · __init__.py
49
+ · datadis.py
50
+ · redata.py
51
+ · processors/
52
+ · __init__.py
53
+ · base.py
54
+ · billing.py
55
+ · consumption.py
56
+ · maximeter.py
57
+ · utils.py
58
+ · helpers.py
59
+ ```
60
+
61
+ ## Ejemplo de uso
62
+
63
+ Partimos de que tenemos credenciales en Datadis.es. Algunas aclaraciones:
64
+ * No es necesario solicitar API pública en el registro (se utilizará la API privada habilitada por defecto)
65
+ * El username suele ser el NIF del titular
66
+ * Copie el CUPS de la web de Datadis, algunas comercializadoras adhieren caracteres adicionales en el CUPS mostrado en su factura.
67
+ * La herramienta acepta el uso de NIF autorizado para consultar el suministro de otro titular.
68
+
69
+ ``` python
70
+ from datetime import datetime
71
+ import json
72
+
73
+ # importamos definiciones de datos que nos interesen
74
+ from edata.definitions import PricingRules
75
+ # importamos el ayudante
76
+ from edata.helpers import EdataHelper
77
+ # importamos el procesador de utilidades
78
+ from edata.processors import utils
79
+
80
+ # Preparar reglas de tarificación (si se quiere)
81
+ PRICING_RULES_PVPC = PricingRules(
82
+ p1_kw_year_eur=30.67266,
83
+ p2_kw_year_eur=1.4243591,
84
+ meter_month_eur=0.81,
85
+ market_kw_year_eur=3.113,
86
+ electricity_tax=1.0511300560,
87
+ iva_tax=1.05,
88
+ # podemos rellenar los siguientes campos si quisiéramos precio fijo (y no pvpc)
89
+ p1_kwh_eur=None,
90
+ p2_kwh_eur=None,
91
+ p3_kwh_eur=None,
92
+ )
93
+
94
+ # Instanciar el helper
95
+ # 'authorized_nif' permite indicar el NIF de la persona que nos autoriza a consultar su CUPS.
96
+ # 'data' permite "cargar" al helper datos anteriores (resultado edata.data de una ejecución anterior), para evitar volver a consultar los mismos.
97
+ edata = EdataHelper(
98
+ "datadis_user",
99
+ "datadis_password",
100
+ "cups",
101
+ datadis_authorized_nif=None,
102
+ pricing_rules=PRICING_RULES_PVPC, # si se le pasa None, no aplica tarificación
103
+ data=None, # aquí podríamos cargar datos anteriores
104
+ )
105
+
106
+ # Solicitar actualización de todo el histórico (se almacena en edata.data)
107
+ edata.update(date_from=datetime(1970, 1, 1), date_to=datetime.today())
108
+
109
+ # volcamos todo lo obtenido a un fichero
110
+ with open("backup.json", "w") as file:
111
+ json.dump(utils.serialize_dict(edata.data), file) # se puede utilizar deserialize_dict para la posterior lectura del backup
112
+
113
+ # Imprimir atributos
114
+ print(edata.attributes)
115
+ ```
116
+
117
+ Platform: UNKNOWN
118
+ Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
119
+ Classifier: Programming Language :: Python
120
+ Classifier: Programming Language :: Python :: 3
121
+ Classifier: Programming Language :: Python :: 3.6
122
+ Classifier: Programming Language :: Python :: 3.7
123
+ Classifier: Programming Language :: Python :: 3.8
124
+ Classifier: Programming Language :: Python :: 3.9
125
+ Classifier: Programming Language :: Python :: Implementation :: CPython
126
+ Classifier: Programming Language :: Python :: Implementation :: PyPy
127
+ Requires-Python: >=3.6.0
128
+ Description-Content-Type: text/markdown
@@ -0,0 +1,128 @@
1
+ Metadata-Version: 2.1
2
+ Name: e-data
3
+ Version: 1.2.18
4
+ Summary: Python library for managing spanish energy data from various web providers
5
+ Home-page: https://github.com/uvejota/python-edata
6
+ Author: VMG
7
+ Author-email: vmayorg@outlook.es
8
+ License: GPLv3
9
+ Description:
10
+ [![Downloads](https://pepy.tech/badge/e-data)](https://pepy.tech/project/e-data)
11
+ [![Downloads](https://pepy.tech/badge/e-data/month)](https://pepy.tech/project/e-data)
12
+ [![Downloads](https://pepy.tech/badge/e-data/week)](https://pepy.tech/project/e-data)
13
+
14
+ # python-edata
15
+
16
+ Este paquete proporciona herramientas para la descarga de tus datos de consumo eléctrico (desde Datadis.es) y su posterior procesado. La motivación principal es que conocer el consumo puede ayudarnos a reducirlo, e incluso a elegir una tarifa que mejor se adapte a nuestras necesidades. A día de hoy sus capacidades de facturación (€) son limitadas, soporta PVPC (según disponibilidad de datos de REData) y tarificación fija por tramos. Es el corazón de la integración [homeassistant-edata](https://github.com/uvejota/homeassistant-edata).
17
+
18
+ _**Esta herramienta no mantiene ningún tipo de vinculación con los proveedores de datos anteriormente mencionados, simplemente consulta la información disponible y facilita su posterior análisis.**_
19
+
20
+ ## Instalación
21
+
22
+ Puedes instalar la última versión estable mediante:
23
+
24
+ ``` bash
25
+ pip install e-data
26
+ ```
27
+
28
+ Si quieres probar la versión `dev` o contribuir a su desarrollo, clona este repositorio e instala manualmente las dependencias:
29
+
30
+ ``` bash
31
+ pip install -r requirements.txt
32
+ ```
33
+
34
+ ## Estructura
35
+
36
+ El paquete consta de tres módulos diferenciados:
37
+
38
+ * **Conectores** (módulo `connectors`), para definir los métodos de consulta a los diferentes proveedores: Datadis y REData.
39
+ * **Procesadores** (módulo `processors`), para procesar datos de consumo, maxímetro, o coste (tarificación). Ahora mismo consta de tres procesadores: `billing`, `consumption` y `maximeter`, además de algunas utilidades ubicadas en `utils`. Los procesadores deben heredar de la clase Processor definida en `base.py`
40
+ * **Ayudantes** (módulo `helpers`), para ayudar en el uso y gestión de los anteriores, presentando de momento un único ayudante llamado `EdataHelper` que te permite recopilar `X` días de datos (por defecto 365) y automáticamente procesarlos. Los datos son almacenados en la variable `data`, mientras que los atributos autocalculados son almacenados en la variable `attributes`. Por lo general, primero utilizan los conectores y luego procesan los datos, gestionando varias tareas de recuperación (principalmente para Datadis).
41
+
42
+ Estos módulos corresponden a la siguiente estructura del paquete:
43
+
44
+ ```
45
+ edata/
46
+ · __init__.py
47
+ · connectors/
48
+ · __init__.py
49
+ · datadis.py
50
+ · redata.py
51
+ · processors/
52
+ · __init__.py
53
+ · base.py
54
+ · billing.py
55
+ · consumption.py
56
+ · maximeter.py
57
+ · utils.py
58
+ · helpers.py
59
+ ```
60
+
61
+ ## Ejemplo de uso
62
+
63
+ Partimos de que tenemos credenciales en Datadis.es. Algunas aclaraciones:
64
+ * No es necesario solicitar API pública en el registro (se utilizará la API privada habilitada por defecto)
65
+ * El username suele ser el NIF del titular
66
+ * Copie el CUPS de la web de Datadis, algunas comercializadoras adhieren caracteres adicionales en el CUPS mostrado en su factura.
67
+ * La herramienta acepta el uso de NIF autorizado para consultar el suministro de otro titular.
68
+
69
+ ``` python
70
+ from datetime import datetime
71
+ import json
72
+
73
+ # importamos definiciones de datos que nos interesen
74
+ from edata.definitions import PricingRules
75
+ # importamos el ayudante
76
+ from edata.helpers import EdataHelper
77
+ # importamos el procesador de utilidades
78
+ from edata.processors import utils
79
+
80
+ # Preparar reglas de tarificación (si se quiere)
81
+ PRICING_RULES_PVPC = PricingRules(
82
+ p1_kw_year_eur=30.67266,
83
+ p2_kw_year_eur=1.4243591,
84
+ meter_month_eur=0.81,
85
+ market_kw_year_eur=3.113,
86
+ electricity_tax=1.0511300560,
87
+ iva_tax=1.05,
88
+ # podemos rellenar los siguientes campos si quisiéramos precio fijo (y no pvpc)
89
+ p1_kwh_eur=None,
90
+ p2_kwh_eur=None,
91
+ p3_kwh_eur=None,
92
+ )
93
+
94
+ # Instanciar el helper
95
+ # 'authorized_nif' permite indicar el NIF de la persona que nos autoriza a consultar su CUPS.
96
+ # 'data' permite "cargar" al helper datos anteriores (resultado edata.data de una ejecución anterior), para evitar volver a consultar los mismos.
97
+ edata = EdataHelper(
98
+ "datadis_user",
99
+ "datadis_password",
100
+ "cups",
101
+ datadis_authorized_nif=None,
102
+ pricing_rules=PRICING_RULES_PVPC, # si se le pasa None, no aplica tarificación
103
+ data=None, # aquí podríamos cargar datos anteriores
104
+ )
105
+
106
+ # Solicitar actualización de todo el histórico (se almacena en edata.data)
107
+ edata.update(date_from=datetime(1970, 1, 1), date_to=datetime.today())
108
+
109
+ # volcamos todo lo obtenido a un fichero
110
+ with open("backup.json", "w") as file:
111
+ json.dump(utils.serialize_dict(edata.data), file) # se puede utilizar deserialize_dict para la posterior lectura del backup
112
+
113
+ # Imprimir atributos
114
+ print(edata.attributes)
115
+ ```
116
+
117
+ Platform: UNKNOWN
118
+ Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
119
+ Classifier: Programming Language :: Python
120
+ Classifier: Programming Language :: Python :: 3
121
+ Classifier: Programming Language :: Python :: 3.6
122
+ Classifier: Programming Language :: Python :: 3.7
123
+ Classifier: Programming Language :: Python :: 3.8
124
+ Classifier: Programming Language :: Python :: 3.9
125
+ Classifier: Programming Language :: Python :: Implementation :: CPython
126
+ Classifier: Programming Language :: Python :: Implementation :: PyPy
127
+ Requires-Python: >=3.6.0
128
+ Description-Content-Type: text/markdown
@@ -4,7 +4,6 @@ To fetch data from datadis.es private API.
4
4
  There a few issues that are workarounded:
5
5
  - You have to wait 24h between two identical requests.
6
6
  - Datadis server does not like ranges greater than 1 month.
7
- - TODO: gzip header checksum errors under weird circumstances
8
7
  """
9
8
 
10
9
  import contextlib
@@ -17,6 +16,8 @@ from dateutil.relativedelta import relativedelta
17
16
 
18
17
  import requests
19
18
 
19
+ from filelock import FileLock
20
+
20
21
  from ..definitions import ConsumptionData, ContractData, MaxPowerData, SupplyData
21
22
  from ..processors import utils
22
23
 
@@ -104,50 +105,59 @@ class DatadisConnector:
104
105
  self._recent_queries_file = DEFAULT_RECENT_QUERIES_FILE
105
106
  self._recent_queries_cache_file = DEFAULT_RECENT_QUERIES_CACHE
106
107
  self._warned_queries = []
108
+ self._load_recent_cache()
109
+
110
+ def _load_recent_cache(self) -> None:
111
+ """Load caches."""
107
112
 
108
- # load caches (to avoid query spam if the program restarts)
109
113
  with contextlib.suppress(FileNotFoundError):
110
114
  with open(self._recent_queries_file, encoding="utf8") as dst_file:
111
- self._recent_queries = json.load(dst_file)
112
- for query in self._recent_queries:
113
- self._recent_queries[query] = datetime.fromisoformat(
114
- self._recent_queries[query]
115
+ recent_queries = json.load(dst_file)
116
+ for query in recent_queries:
117
+ recent_queries[query] = datetime.fromisoformat(
118
+ recent_queries[query]
115
119
  )
120
+ self._recent_queries.update(recent_queries)
121
+
116
122
  with open(self._recent_queries_cache_file, encoding="utf8") as dst_file:
117
- self._recent_cache = json.load(dst_file)
123
+ self._recent_cache.update(json.load(dst_file))
118
124
 
119
125
  def _update_recent_queries(self, query: str, data: dict | None = None) -> None:
120
126
  """Cache a successful query to avoid exceeding query limits."""
121
127
 
122
- # identify the query by a md5 hash
123
- hash_query = hashlib.md5(query.encode()).hexdigest()
124
- # prepare key (hash) and values (timestamp and response)
125
- self._recent_queries[hash_query] = datetime.now()
126
- if data is not None:
127
- self._recent_cache[hash_query] = data
128
-
129
- # purge old cache
130
- to_delete = []
131
- for _query in self._recent_queries:
132
- if (datetime.now() - self._recent_queries[_query]) > QUERY_LIMIT:
133
- to_delete.append(_query)
134
-
135
- for key in to_delete:
136
- with contextlib.suppress(KeyError):
137
- self._recent_queries.pop(key, None)
138
- self._recent_cache.pop(key, None)
139
-
140
- # dump current cache to disk
141
- try:
142
- with open(self._recent_queries_file, "w", encoding="utf8") as dst_file:
143
- json.dump(utils.serialize_dict(self._recent_queries), dst_file)
128
+ with FileLock(self._recent_queries_file + ".lock"):
129
+ self._load_recent_cache()
130
+ # identify the query by a md5 hash
131
+ hash_query = hashlib.md5(query.encode()).hexdigest()
132
+ # prepare key (hash) and values (timestamp and response)
133
+ self._recent_queries[hash_query] = datetime.now()
144
134
  if data is not None:
145
- with open(
146
- self._recent_queries_cache_file, "w", encoding="utf8"
147
- ) as dst_file:
148
- json.dump(self._recent_cache, dst_file)
149
- except Exception as e:
150
- _LOGGER.warning("Unknown error while updating cache: %s", e)
135
+ self._recent_cache[hash_query] = data
136
+
137
+ # purge old cache
138
+ to_delete = [
139
+ x
140
+ for x in self._recent_queries
141
+ if (datetime.now() - self._recent_queries[x]) > QUERY_LIMIT
142
+ ]
143
+
144
+ for key in to_delete:
145
+ with contextlib.suppress(KeyError):
146
+ self._recent_queries.pop(key, None)
147
+ self._recent_cache.pop(key, None)
148
+
149
+ # dump current cache to disk
150
+ try:
151
+ with open(self._recent_queries_file, "w", encoding="utf8") as dst_file:
152
+ json.dump(utils.serialize_dict(self._recent_queries), dst_file)
153
+ if data is not None:
154
+ with open(
155
+ self._recent_queries_cache_file, "w", encoding="utf8"
156
+ ) as dst_file:
157
+ json.dump(self._recent_cache, dst_file)
158
+ _LOGGER.info("Local cache updated")
159
+ except Exception as e:
160
+ _LOGGER.warning("Unknown error while updating cache: %s", e)
151
161
 
152
162
  def _is_recent_query(self, query: str) -> bool:
153
163
  """Check if a query has been done recently to avoid exceeding query limits."""
@@ -160,7 +170,7 @@ class DatadisConnector:
160
170
  def _get_cache_for_query(self, query: str) -> dict:
161
171
  """Return cached response for a query."""
162
172
  hash_query = hashlib.md5(query.encode()).hexdigest()
163
-
173
+ _LOGGER.info("Serving '%s' from cache", query)
164
174
  return self._recent_cache.get(hash_query, None)
165
175
 
166
176
  def _get_token(self):
@@ -302,7 +312,7 @@ class DatadisConnector:
302
312
 
303
313
  # Request the resource
304
314
  response = self._get(
305
- URL_GET_SUPPLIES, request_data=data, ignore_recent_queries=False
315
+ URL_GET_SUPPLIES, request_data=data, ignore_recent_queries=True
306
316
  )
307
317
 
308
318
  # Response is a list of serialized supplies.
@@ -318,23 +328,27 @@ class DatadisConnector:
318
328
  SupplyData(
319
329
  cups=i["cups"], # the supply identifier
320
330
  date_start=datetime.strptime(
321
- i["validDateFrom"]
322
- if i["validDateFrom"] != ""
323
- else "1970/01/01",
331
+ (
332
+ i["validDateFrom"]
333
+ if i["validDateFrom"] != ""
334
+ else "1970/01/01"
335
+ ),
324
336
  "%Y/%m/%d",
325
337
  ), # start date of the supply. 1970/01/01 if unset.
326
338
  date_end=datetime.strptime(
327
- i["validDateTo"]
328
- if i["validDateTo"] != ""
329
- else tomorrow_str,
339
+ (
340
+ i["validDateTo"]
341
+ if i["validDateTo"] != ""
342
+ else tomorrow_str
343
+ ),
330
344
  "%Y/%m/%d",
331
345
  ), # end date of the supply, tomorrow if unset
332
346
  # the following parameters are not crucial, so they can be none
333
- address=i["address"] if "address" in i else None,
334
- postal_code=i["postalCode"] if "postalCode" in i else None,
335
- province=i["province"] if "province" in i else None,
336
- municipality=i["municipality"] if "municipality" in i else None,
337
- distributor=i["distributor"] if "distributor" in i else None,
347
+ address=i.get("address", None),
348
+ postal_code=i.get("postalCode", None),
349
+ province=i.get("province", None),
350
+ municipality=i.get("municipality", None),
351
+ distributor=i.get("distributor", None),
338
352
  # these two are mandatory, we will use them to fetch contracts data
339
353
  pointType=i["pointType"],
340
354
  distributorCode=i["distributorCode"],
@@ -355,7 +369,7 @@ class DatadisConnector:
355
369
  if authorized_nif is not None:
356
370
  data["authorizedNif"] = authorized_nif
357
371
  response = self._get(
358
- URL_GET_CONTRACT_DETAIL, request_data=data, ignore_recent_queries=False
372
+ URL_GET_CONTRACT_DETAIL, request_data=data, ignore_recent_queries=True
359
373
  )
360
374
  contracts = []
361
375
  tomorrow_str = (datetime.today() + timedelta(days=1)).strftime("%Y/%m/%d")
@@ -373,12 +387,16 @@ class DatadisConnector:
373
387
  ),
374
388
  marketer=i["marketer"],
375
389
  distributorCode=distributor_code,
376
- power_p1=i["contractedPowerkW"][0]
377
- if isinstance(i["contractedPowerkW"], list)
378
- else None,
379
- power_p2=i["contractedPowerkW"][1]
380
- if (len(i["contractedPowerkW"]) > 1)
381
- else None,
390
+ power_p1=(
391
+ i["contractedPowerkW"][0]
392
+ if isinstance(i["contractedPowerkW"], list)
393
+ else None
394
+ ),
395
+ power_p2=(
396
+ i["contractedPowerkW"][1]
397
+ if (len(i["contractedPowerkW"]) > 1)
398
+ else None
399
+ ),
382
400
  )
383
401
  )
384
402
  else:
@@ -74,9 +74,11 @@ class EdataHelper:
74
74
  self.datadis_api = DatadisConnector(
75
75
  datadis_username,
76
76
  datadis_password,
77
- storage_path=os.path.join(storage_dir_path, const.PROG_NAME)
78
- if storage_dir_path is not None
79
- else None,
77
+ storage_path=(
78
+ os.path.join(storage_dir_path, const.PROG_NAME)
79
+ if storage_dir_path is not None
80
+ else None
81
+ ),
80
82
  )
81
83
  self.redata_api = REDataConnector()
82
84
 
@@ -679,11 +681,11 @@ class EdataHelper:
679
681
  for x in self.data["consumptions"]
680
682
  if x["datetime"] >= new_data_from
681
683
  ],
682
- prices=[
683
- x for x in self.data["pvpc"] if x["datetime"] >= new_data_from
684
- ]
685
- if self.is_pvpc
686
- else None,
684
+ prices=(
685
+ [x for x in self.data["pvpc"] if x["datetime"] >= new_data_from]
686
+ if self.is_pvpc
687
+ else None
688
+ ),
687
689
  rules=self.pricing_rules,
688
690
  )
689
691
  )
@@ -20,7 +20,7 @@ URL = "https://github.com/uvejota/python-edata"
20
20
  EMAIL = "vmayorg@outlook.es"
21
21
  AUTHOR = "VMG"
22
22
  REQUIRES_PYTHON = ">=3.6.0"
23
- VERSION = "1.2.17"
23
+ VERSION = "1.2.18"
24
24
 
25
25
  # What packages are required for this module to be executed?
26
26
  REQUIRED = [
e-data-1.2.17/PKG-INFO DELETED
@@ -1,128 +0,0 @@
1
- Metadata-Version: 2.1
2
- Name: e-data
3
- Version: 1.2.17
4
- Summary: Python library for managing spanish energy data from various web providers
5
- Home-page: https://github.com/uvejota/python-edata
6
- Author: VMG
7
- Author-email: vmayorg@outlook.es
8
- License: GPLv3
9
- Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
10
- Classifier: Programming Language :: Python
11
- Classifier: Programming Language :: Python :: 3
12
- Classifier: Programming Language :: Python :: 3.6
13
- Classifier: Programming Language :: Python :: 3.7
14
- Classifier: Programming Language :: Python :: 3.8
15
- Classifier: Programming Language :: Python :: 3.9
16
- Classifier: Programming Language :: Python :: Implementation :: CPython
17
- Classifier: Programming Language :: Python :: Implementation :: PyPy
18
- Requires-Python: >=3.6.0
19
- Description-Content-Type: text/markdown
20
- License-File: LICENSE
21
-
22
-
23
- [![Downloads](https://pepy.tech/badge/e-data)](https://pepy.tech/project/e-data)
24
- [![Downloads](https://pepy.tech/badge/e-data/month)](https://pepy.tech/project/e-data)
25
- [![Downloads](https://pepy.tech/badge/e-data/week)](https://pepy.tech/project/e-data)
26
-
27
- # python-edata
28
-
29
- Este paquete proporciona herramientas para la descarga de tus datos de consumo eléctrico (desde Datadis.es) y su posterior procesado. La motivación principal es que conocer el consumo puede ayudarnos a reducirlo, e incluso a elegir una tarifa que mejor se adapte a nuestras necesidades. A día de hoy sus capacidades de facturación (€) son limitadas, soporta PVPC (según disponibilidad de datos de REData) y tarificación fija por tramos. Es el corazón de la integración [homeassistant-edata](https://github.com/uvejota/homeassistant-edata).
30
-
31
- _**Esta herramienta no mantiene ningún tipo de vinculación con los proveedores de datos anteriormente mencionados, simplemente consulta la información disponible y facilita su posterior análisis.**_
32
-
33
- ## Instalación
34
-
35
- Puedes instalar la última versión estable mediante:
36
-
37
- ``` bash
38
- pip install e-data
39
- ```
40
-
41
- Si quieres probar la versión `dev` o contribuir a su desarrollo, clona este repositorio e instala manualmente las dependencias:
42
-
43
- ``` bash
44
- pip install -r requirements.txt
45
- ```
46
-
47
- ## Estructura
48
-
49
- El paquete consta de tres módulos diferenciados:
50
-
51
- * **Conectores** (módulo `connectors`), para definir los métodos de consulta a los diferentes proveedores: Datadis y REData.
52
- * **Procesadores** (módulo `processors`), para procesar datos de consumo, maxímetro, o coste (tarificación). Ahora mismo consta de tres procesadores: `billing`, `consumption` y `maximeter`, además de algunas utilidades ubicadas en `utils`. Los procesadores deben heredar de la clase Processor definida en `base.py`
53
- * **Ayudantes** (módulo `helpers`), para ayudar en el uso y gestión de los anteriores, presentando de momento un único ayudante llamado `EdataHelper` que te permite recopilar `X` días de datos (por defecto 365) y automáticamente procesarlos. Los datos son almacenados en la variable `data`, mientras que los atributos autocalculados son almacenados en la variable `attributes`. Por lo general, primero utilizan los conectores y luego procesan los datos, gestionando varias tareas de recuperación (principalmente para Datadis).
54
-
55
- Estos módulos corresponden a la siguiente estructura del paquete:
56
-
57
- ```
58
- edata/
59
- · __init__.py
60
- · connectors/
61
- · __init__.py
62
- · datadis.py
63
- · redata.py
64
- · processors/
65
- · __init__.py
66
- · base.py
67
- · billing.py
68
- · consumption.py
69
- · maximeter.py
70
- · utils.py
71
- · helpers.py
72
- ```
73
-
74
- ## Ejemplo de uso
75
-
76
- Partimos de que tenemos credenciales en Datadis.es. Algunas aclaraciones:
77
- * No es necesario solicitar API pública en el registro (se utilizará la API privada habilitada por defecto)
78
- * El username suele ser el NIF del titular
79
- * Copie el CUPS de la web de Datadis, algunas comercializadoras adhieren caracteres adicionales en el CUPS mostrado en su factura.
80
- * La herramienta acepta el uso de NIF autorizado para consultar el suministro de otro titular.
81
-
82
- ``` python
83
- from datetime import datetime
84
- import json
85
-
86
- # importamos definiciones de datos que nos interesen
87
- from edata.definitions import PricingRules
88
- # importamos el ayudante
89
- from edata.helpers import EdataHelper
90
- # importamos el procesador de utilidades
91
- from edata.processors import utils
92
-
93
- # Preparar reglas de tarificación (si se quiere)
94
- PRICING_RULES_PVPC = PricingRules(
95
- p1_kw_year_eur=30.67266,
96
- p2_kw_year_eur=1.4243591,
97
- meter_month_eur=0.81,
98
- market_kw_year_eur=3.113,
99
- electricity_tax=1.0511300560,
100
- iva_tax=1.05,
101
- # podemos rellenar los siguientes campos si quisiéramos precio fijo (y no pvpc)
102
- p1_kwh_eur=None,
103
- p2_kwh_eur=None,
104
- p3_kwh_eur=None,
105
- )
106
-
107
- # Instanciar el helper
108
- # 'authorized_nif' permite indicar el NIF de la persona que nos autoriza a consultar su CUPS.
109
- # 'data' permite "cargar" al helper datos anteriores (resultado edata.data de una ejecución anterior), para evitar volver a consultar los mismos.
110
- edata = EdataHelper(
111
- "datadis_user",
112
- "datadis_password",
113
- "cups",
114
- datadis_authorized_nif=None,
115
- pricing_rules=PRICING_RULES_PVPC, # si se le pasa None, no aplica tarificación
116
- data=None, # aquí podríamos cargar datos anteriores
117
- )
118
-
119
- # Solicitar actualización de todo el histórico (se almacena en edata.data)
120
- edata.update(date_from=datetime(1970, 1, 1), date_to=datetime.today())
121
-
122
- # volcamos todo lo obtenido a un fichero
123
- with open("backup.json", "w") as file:
124
- json.dump(utils.serialize_dict(edata.data), file) # se puede utilizar deserialize_dict para la posterior lectura del backup
125
-
126
- # Imprimir atributos
127
- print(edata.attributes)
128
- ```
@@ -1,128 +0,0 @@
1
- Metadata-Version: 2.1
2
- Name: e-data
3
- Version: 1.2.17
4
- Summary: Python library for managing spanish energy data from various web providers
5
- Home-page: https://github.com/uvejota/python-edata
6
- Author: VMG
7
- Author-email: vmayorg@outlook.es
8
- License: GPLv3
9
- Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
10
- Classifier: Programming Language :: Python
11
- Classifier: Programming Language :: Python :: 3
12
- Classifier: Programming Language :: Python :: 3.6
13
- Classifier: Programming Language :: Python :: 3.7
14
- Classifier: Programming Language :: Python :: 3.8
15
- Classifier: Programming Language :: Python :: 3.9
16
- Classifier: Programming Language :: Python :: Implementation :: CPython
17
- Classifier: Programming Language :: Python :: Implementation :: PyPy
18
- Requires-Python: >=3.6.0
19
- Description-Content-Type: text/markdown
20
- License-File: LICENSE
21
-
22
-
23
- [![Downloads](https://pepy.tech/badge/e-data)](https://pepy.tech/project/e-data)
24
- [![Downloads](https://pepy.tech/badge/e-data/month)](https://pepy.tech/project/e-data)
25
- [![Downloads](https://pepy.tech/badge/e-data/week)](https://pepy.tech/project/e-data)
26
-
27
- # python-edata
28
-
29
- Este paquete proporciona herramientas para la descarga de tus datos de consumo eléctrico (desde Datadis.es) y su posterior procesado. La motivación principal es que conocer el consumo puede ayudarnos a reducirlo, e incluso a elegir una tarifa que mejor se adapte a nuestras necesidades. A día de hoy sus capacidades de facturación (€) son limitadas, soporta PVPC (según disponibilidad de datos de REData) y tarificación fija por tramos. Es el corazón de la integración [homeassistant-edata](https://github.com/uvejota/homeassistant-edata).
30
-
31
- _**Esta herramienta no mantiene ningún tipo de vinculación con los proveedores de datos anteriormente mencionados, simplemente consulta la información disponible y facilita su posterior análisis.**_
32
-
33
- ## Instalación
34
-
35
- Puedes instalar la última versión estable mediante:
36
-
37
- ``` bash
38
- pip install e-data
39
- ```
40
-
41
- Si quieres probar la versión `dev` o contribuir a su desarrollo, clona este repositorio e instala manualmente las dependencias:
42
-
43
- ``` bash
44
- pip install -r requirements.txt
45
- ```
46
-
47
- ## Estructura
48
-
49
- El paquete consta de tres módulos diferenciados:
50
-
51
- * **Conectores** (módulo `connectors`), para definir los métodos de consulta a los diferentes proveedores: Datadis y REData.
52
- * **Procesadores** (módulo `processors`), para procesar datos de consumo, maxímetro, o coste (tarificación). Ahora mismo consta de tres procesadores: `billing`, `consumption` y `maximeter`, además de algunas utilidades ubicadas en `utils`. Los procesadores deben heredar de la clase Processor definida en `base.py`
53
- * **Ayudantes** (módulo `helpers`), para ayudar en el uso y gestión de los anteriores, presentando de momento un único ayudante llamado `EdataHelper` que te permite recopilar `X` días de datos (por defecto 365) y automáticamente procesarlos. Los datos son almacenados en la variable `data`, mientras que los atributos autocalculados son almacenados en la variable `attributes`. Por lo general, primero utilizan los conectores y luego procesan los datos, gestionando varias tareas de recuperación (principalmente para Datadis).
54
-
55
- Estos módulos corresponden a la siguiente estructura del paquete:
56
-
57
- ```
58
- edata/
59
- · __init__.py
60
- · connectors/
61
- · __init__.py
62
- · datadis.py
63
- · redata.py
64
- · processors/
65
- · __init__.py
66
- · base.py
67
- · billing.py
68
- · consumption.py
69
- · maximeter.py
70
- · utils.py
71
- · helpers.py
72
- ```
73
-
74
- ## Ejemplo de uso
75
-
76
- Partimos de que tenemos credenciales en Datadis.es. Algunas aclaraciones:
77
- * No es necesario solicitar API pública en el registro (se utilizará la API privada habilitada por defecto)
78
- * El username suele ser el NIF del titular
79
- * Copie el CUPS de la web de Datadis, algunas comercializadoras adhieren caracteres adicionales en el CUPS mostrado en su factura.
80
- * La herramienta acepta el uso de NIF autorizado para consultar el suministro de otro titular.
81
-
82
- ``` python
83
- from datetime import datetime
84
- import json
85
-
86
- # importamos definiciones de datos que nos interesen
87
- from edata.definitions import PricingRules
88
- # importamos el ayudante
89
- from edata.helpers import EdataHelper
90
- # importamos el procesador de utilidades
91
- from edata.processors import utils
92
-
93
- # Preparar reglas de tarificación (si se quiere)
94
- PRICING_RULES_PVPC = PricingRules(
95
- p1_kw_year_eur=30.67266,
96
- p2_kw_year_eur=1.4243591,
97
- meter_month_eur=0.81,
98
- market_kw_year_eur=3.113,
99
- electricity_tax=1.0511300560,
100
- iva_tax=1.05,
101
- # podemos rellenar los siguientes campos si quisiéramos precio fijo (y no pvpc)
102
- p1_kwh_eur=None,
103
- p2_kwh_eur=None,
104
- p3_kwh_eur=None,
105
- )
106
-
107
- # Instanciar el helper
108
- # 'authorized_nif' permite indicar el NIF de la persona que nos autoriza a consultar su CUPS.
109
- # 'data' permite "cargar" al helper datos anteriores (resultado edata.data de una ejecución anterior), para evitar volver a consultar los mismos.
110
- edata = EdataHelper(
111
- "datadis_user",
112
- "datadis_password",
113
- "cups",
114
- datadis_authorized_nif=None,
115
- pricing_rules=PRICING_RULES_PVPC, # si se le pasa None, no aplica tarificación
116
- data=None, # aquí podríamos cargar datos anteriores
117
- )
118
-
119
- # Solicitar actualización de todo el histórico (se almacena en edata.data)
120
- edata.update(date_from=datetime(1970, 1, 1), date_to=datetime.today())
121
-
122
- # volcamos todo lo obtenido a un fichero
123
- with open("backup.json", "w") as file:
124
- json.dump(utils.serialize_dict(edata.data), file) # se puede utilizar deserialize_dict para la posterior lectura del backup
125
-
126
- # Imprimir atributos
127
- print(edata.attributes)
128
- ```
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes