myelectricaldatapy 2.2.9__tar.gz → 2.3.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.
- {myelectricaldatapy-2.2.9 → myelectricaldatapy-2.3.0}/.github/workflows/release.yml +0 -8
- {myelectricaldatapy-2.2.9 → myelectricaldatapy-2.3.0}/PKG-INFO +25 -2
- {myelectricaldatapy-2.2.9 → myelectricaldatapy-2.3.0}/README.md +24 -0
- myelectricaldatapy-2.3.0/myelectricaldatapy/__init__.py +48 -0
- {myelectricaldatapy-2.2.9 → myelectricaldatapy-2.3.0}/myelectricaldatapy/api.py +9 -12
- {myelectricaldatapy-2.2.9 → myelectricaldatapy-2.3.0}/myelectricaldatapy/auth.py +5 -5
- myelectricaldatapy-2.3.0/myelectricaldatapy/const.py +25 -0
- {myelectricaldatapy-2.2.9 → myelectricaldatapy-2.3.0}/myelectricaldatapy/mypdl.py +153 -161
- myelectricaldatapy-2.3.0/myelectricaldatapy/types.py +71 -0
- {myelectricaldatapy-2.2.9 → myelectricaldatapy-2.3.0}/myelectricaldatapy.egg-info/PKG-INFO +25 -2
- {myelectricaldatapy-2.2.9 → myelectricaldatapy-2.3.0}/myelectricaldatapy.egg-info/SOURCES.txt +2 -0
- {myelectricaldatapy-2.2.9 → myelectricaldatapy-2.3.0}/myelectricaldatapy.egg-info/requires.txt +0 -1
- {myelectricaldatapy-2.2.9 → myelectricaldatapy-2.3.0}/myelectricaldatapy.egg-info/scm_file_list.json +3 -1
- myelectricaldatapy-2.3.0/myelectricaldatapy.egg-info/scm_version.json +8 -0
- {myelectricaldatapy-2.2.9 → myelectricaldatapy-2.3.0}/pyproject.toml +0 -1
- {myelectricaldatapy-2.2.9 → myelectricaldatapy-2.3.0}/tests/conftest.py +2 -28
- myelectricaldatapy-2.3.0/tests/test_analytics.py +346 -0
- {myelectricaldatapy-2.2.9 → myelectricaldatapy-2.3.0}/tests/test_load_data.py +21 -14
- myelectricaldatapy-2.3.0/uv.lock +1008 -0
- myelectricaldatapy-2.2.9/myelectricaldatapy/__init__.py +0 -22
- myelectricaldatapy-2.2.9/myelectricaldatapy/const.py +0 -21
- myelectricaldatapy-2.2.9/myelectricaldatapy.egg-info/scm_version.json +0 -8
- myelectricaldatapy-2.2.9/tests/test_analytics.py +0 -361
- {myelectricaldatapy-2.2.9 → myelectricaldatapy-2.3.0}/.devcontainer/devcontainer-lock.json +0 -0
- {myelectricaldatapy-2.2.9 → myelectricaldatapy-2.3.0}/.devcontainer/devcontainer.json +0 -0
- {myelectricaldatapy-2.2.9 → myelectricaldatapy-2.3.0}/.github/dependabot.yml +0 -0
- {myelectricaldatapy-2.2.9 → myelectricaldatapy-2.3.0}/.github/workflows/auto-approve.yml +0 -0
- {myelectricaldatapy-2.2.9 → myelectricaldatapy-2.3.0}/.github/workflows/python-lint.yml +0 -0
- {myelectricaldatapy-2.2.9 → myelectricaldatapy-2.3.0}/.github/workflows/python-publish.yml +0 -0
- {myelectricaldatapy-2.2.9 → myelectricaldatapy-2.3.0}/.gitignore +0 -0
- {myelectricaldatapy-2.2.9 → myelectricaldatapy-2.3.0}/.pre-commit-config.yaml +0 -0
- {myelectricaldatapy-2.2.9 → myelectricaldatapy-2.3.0}/.vscode/settings.json +0 -0
- {myelectricaldatapy-2.2.9 → myelectricaldatapy-2.3.0}/LICENSE +0 -0
- {myelectricaldatapy-2.2.9 → myelectricaldatapy-2.3.0}/_secrets.yaml +0 -0
- {myelectricaldatapy-2.2.9 → myelectricaldatapy-2.3.0}/example.py +0 -0
- {myelectricaldatapy-2.2.9 → myelectricaldatapy-2.3.0}/myelectricaldatapy/analytics.py +0 -0
- {myelectricaldatapy-2.2.9 → myelectricaldatapy-2.3.0}/myelectricaldatapy/exceptions.py +0 -0
- {myelectricaldatapy-2.2.9 → myelectricaldatapy-2.3.0}/myelectricaldatapy/py.typed +0 -0
- {myelectricaldatapy-2.2.9 → myelectricaldatapy-2.3.0}/myelectricaldatapy/tz.py +0 -0
- {myelectricaldatapy-2.2.9 → myelectricaldatapy-2.3.0}/myelectricaldatapy.egg-info/dependency_links.txt +0 -0
- {myelectricaldatapy-2.2.9 → myelectricaldatapy-2.3.0}/myelectricaldatapy.egg-info/top_level.txt +0 -0
- {myelectricaldatapy-2.2.9 → myelectricaldatapy-2.3.0}/setup.cfg +0 -0
- {myelectricaldatapy-2.2.9 → myelectricaldatapy-2.3.0}/tests/__init__.py +0 -0
- {myelectricaldatapy-2.2.9 → myelectricaldatapy-2.3.0}/tests/consts.py +0 -0
- {myelectricaldatapy-2.2.9 → myelectricaldatapy-2.3.0}/tests/fixtures/access.json +0 -0
- {myelectricaldatapy-2.2.9 → myelectricaldatapy-2.3.0}/tests/fixtures/address.json +0 -0
- {myelectricaldatapy-2.2.9 → myelectricaldatapy-2.3.0}/tests/fixtures/contract.json +0 -0
- {myelectricaldatapy-2.2.9 → myelectricaldatapy-2.3.0}/tests/fixtures/daily.json +0 -0
- {myelectricaldatapy-2.2.9 → myelectricaldatapy-2.3.0}/tests/fixtures/detail.json +0 -0
- {myelectricaldatapy-2.2.9 → myelectricaldatapy-2.3.0}/tests/fixtures/ecowatt.json +0 -0
- {myelectricaldatapy-2.2.9 → myelectricaldatapy-2.3.0}/tests/fixtures/invalid_access.json +0 -0
- {myelectricaldatapy-2.2.9 → myelectricaldatapy-2.3.0}/tests/fixtures/tempo.json +0 -0
|
@@ -25,11 +25,3 @@ jobs:
|
|
|
25
25
|
draft: false
|
|
26
26
|
prerelease: ${{ contains(github.ref_name, '-') }}
|
|
27
27
|
token: ${{ secrets.GITHUB_TOKEN }}
|
|
28
|
-
publish:
|
|
29
|
-
needs: release
|
|
30
|
-
permissions:
|
|
31
|
-
contents: write
|
|
32
|
-
packages: write
|
|
33
|
-
id-token: write
|
|
34
|
-
if: ${{ ! contains(github.ref_name, '-') }}
|
|
35
|
-
uses: ./.github/workflows/python-publish.yml
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: myelectricaldatapy
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.3.0
|
|
4
4
|
Summary: Fetch Linky data from myelectricaldata.fr
|
|
5
5
|
Author-email: Cyr-ius <cyr-ius@ipocus.net>
|
|
6
6
|
License-Expression: GPL-3.0-or-later
|
|
@@ -21,7 +21,6 @@ Description-Content-Type: text/markdown
|
|
|
21
21
|
License-File: LICENSE
|
|
22
22
|
Requires-Dist: aiohttp>=3.8.1
|
|
23
23
|
Requires-Dist: pandas>=2.0.2
|
|
24
|
-
Requires-Dist: voluptuous>=0.13.1
|
|
25
24
|
Provides-Extra: dev
|
|
26
25
|
Requires-Dist: prek; extra == "dev"
|
|
27
26
|
Requires-Dist: ruff; extra == "dev"
|
|
@@ -76,6 +75,30 @@ $ python setup.py install
|
|
|
76
75
|
- async_load (start: datetime, end: datetime) Return None - Load Data in power_Data attribute
|
|
77
76
|
- async_refresh Return None - Refresh power_Data , tempo_day and ecowatt attributes.
|
|
78
77
|
|
|
78
|
+
## Timezone
|
|
79
|
+
|
|
80
|
+
Enedis/RTE APIs return naive timestamps that represent local wall-clock time. This
|
|
81
|
+
library needs to know which timezone that is in order to compute things like
|
|
82
|
+
off-peak hours or hourly statistics correctly.
|
|
83
|
+
|
|
84
|
+
By default it falls back to the timezone of the host machine running the code
|
|
85
|
+
(`/etc/localtime`), but that has no reason to match the timezone your
|
|
86
|
+
application is actually configured for (e.g. Home Assistant's
|
|
87
|
+
`hass.config.time_zone`). Pass it explicitly to avoid a fixed-offset shift in
|
|
88
|
+
the reported times:
|
|
89
|
+
|
|
90
|
+
```python
|
|
91
|
+
api = EnedisByPDL(token=TOKEN, pdl=PDL, timezone=ZoneInfo("Europe/Paris"))
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Alternatively, set it once globally for every instance:
|
|
95
|
+
|
|
96
|
+
```python
|
|
97
|
+
from myelectricaldatapy import set_local_timezone
|
|
98
|
+
|
|
99
|
+
set_local_timezone(ZoneInfo("Europe/Paris"))
|
|
100
|
+
```
|
|
101
|
+
|
|
79
102
|
## Get started
|
|
80
103
|
|
|
81
104
|
```python
|
|
@@ -41,6 +41,30 @@ $ python setup.py install
|
|
|
41
41
|
- async_load (start: datetime, end: datetime) Return None - Load Data in power_Data attribute
|
|
42
42
|
- async_refresh Return None - Refresh power_Data , tempo_day and ecowatt attributes.
|
|
43
43
|
|
|
44
|
+
## Timezone
|
|
45
|
+
|
|
46
|
+
Enedis/RTE APIs return naive timestamps that represent local wall-clock time. This
|
|
47
|
+
library needs to know which timezone that is in order to compute things like
|
|
48
|
+
off-peak hours or hourly statistics correctly.
|
|
49
|
+
|
|
50
|
+
By default it falls back to the timezone of the host machine running the code
|
|
51
|
+
(`/etc/localtime`), but that has no reason to match the timezone your
|
|
52
|
+
application is actually configured for (e.g. Home Assistant's
|
|
53
|
+
`hass.config.time_zone`). Pass it explicitly to avoid a fixed-offset shift in
|
|
54
|
+
the reported times:
|
|
55
|
+
|
|
56
|
+
```python
|
|
57
|
+
api = EnedisByPDL(token=TOKEN, pdl=PDL, timezone=ZoneInfo("Europe/Paris"))
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Alternatively, set it once globally for every instance:
|
|
61
|
+
|
|
62
|
+
```python
|
|
63
|
+
from myelectricaldatapy import set_local_timezone
|
|
64
|
+
|
|
65
|
+
set_local_timezone(ZoneInfo("Europe/Paris"))
|
|
66
|
+
```
|
|
67
|
+
|
|
44
68
|
## Get started
|
|
45
69
|
|
|
46
70
|
```python
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"""myelectricaldatapy package."""
|
|
2
|
+
|
|
3
|
+
from .api import Enedis
|
|
4
|
+
from .const import *
|
|
5
|
+
from .exceptions import (
|
|
6
|
+
EnedisException,
|
|
7
|
+
HttpRequestError,
|
|
8
|
+
LimitReached,
|
|
9
|
+
TimeoutExceededError,
|
|
10
|
+
)
|
|
11
|
+
from .mypdl import EnedisByPDL, FormatError, validate_cumsum, validate_prices
|
|
12
|
+
from .types import (
|
|
13
|
+
ConsumptionCollect,
|
|
14
|
+
Cum,
|
|
15
|
+
EnergyCollect,
|
|
16
|
+
Mode,
|
|
17
|
+
Prices,
|
|
18
|
+
ProductionCollect,
|
|
19
|
+
Service,
|
|
20
|
+
StandardPrice,
|
|
21
|
+
Subscription,
|
|
22
|
+
TempoPrice,
|
|
23
|
+
)
|
|
24
|
+
from .tz import get_local_timezone, set_local_timezone
|
|
25
|
+
|
|
26
|
+
__all__ = [
|
|
27
|
+
"ConsumptionCollect",
|
|
28
|
+
"Cum",
|
|
29
|
+
"Enedis",
|
|
30
|
+
"EnedisByPDL",
|
|
31
|
+
"EnedisException",
|
|
32
|
+
"EnergyCollect",
|
|
33
|
+
"FormatError",
|
|
34
|
+
"HttpRequestError",
|
|
35
|
+
"LimitReached",
|
|
36
|
+
"Mode",
|
|
37
|
+
"Prices",
|
|
38
|
+
"ProductionCollect",
|
|
39
|
+
"Service",
|
|
40
|
+
"StandardPrice",
|
|
41
|
+
"Subscription",
|
|
42
|
+
"TempoPrice",
|
|
43
|
+
"TimeoutExceededError",
|
|
44
|
+
"get_local_timezone",
|
|
45
|
+
"set_local_timezone",
|
|
46
|
+
"validate_cumsum",
|
|
47
|
+
"validate_prices",
|
|
48
|
+
]
|
|
@@ -9,8 +9,9 @@ from typing import Any
|
|
|
9
9
|
from aiohttp import ClientSession
|
|
10
10
|
|
|
11
11
|
from .auth import EnedisAuth
|
|
12
|
-
from .const import DAILY_CONSUM, DAILY_PROD, DETAIL_CONSUM, DETAIL_PROD
|
|
12
|
+
from .const import DAILY_CONSUM, DAILY_PROD, DETAIL_CONSUM, DETAIL_PROD
|
|
13
13
|
from .exceptions import EnedisException
|
|
14
|
+
from .types import Service
|
|
14
15
|
from .tz import as_local, get_local_timezone, local_now
|
|
15
16
|
|
|
16
17
|
_LOGGER = logging.getLogger(__name__)
|
|
@@ -20,7 +21,7 @@ class Enedis:
|
|
|
20
21
|
"""Enedis API."""
|
|
21
22
|
|
|
22
23
|
def __init__(
|
|
23
|
-
self, token: str, session: ClientSession | None = None, timeout: int =
|
|
24
|
+
self, token: str, session: ClientSession | None = None, timeout: int = 30
|
|
24
25
|
) -> None:
|
|
25
26
|
"""Initialize."""
|
|
26
27
|
session = session or ClientSession()
|
|
@@ -30,15 +31,9 @@ class Enedis:
|
|
|
30
31
|
self.last_access: date | None = None
|
|
31
32
|
|
|
32
33
|
async def async_fetch_datas(
|
|
33
|
-
self, service:
|
|
34
|
+
self, service: Service, pdl: str, start: dt | None = None, end: dt | None = None
|
|
34
35
|
) -> Any:
|
|
35
|
-
"""Retrieve date from service.
|
|
36
|
-
|
|
37
|
-
service: contracts, identity, contact, addresses,
|
|
38
|
-
daily_consumption_max_power,
|
|
39
|
-
daily_consumption, daily_production,
|
|
40
|
-
consumption_load_curve, production_load_curve
|
|
41
|
-
"""
|
|
36
|
+
"""Retrieve date from service."""
|
|
42
37
|
self.last_access = local_now()
|
|
43
38
|
path_range = ""
|
|
44
39
|
if start and end:
|
|
@@ -169,7 +164,9 @@ class Enedis:
|
|
|
169
164
|
"daily_consumption_max_power", pdl, start, end
|
|
170
165
|
)
|
|
171
166
|
|
|
172
|
-
async def _async_get_details(
|
|
167
|
+
async def _async_get_details(
|
|
168
|
+
self, service: Service, pdl: str, start: dt, end: dt
|
|
169
|
+
) -> Any:
|
|
173
170
|
"""Get production details. (max: 7 days)."""
|
|
174
171
|
data = None
|
|
175
172
|
response: dict[str, Any] | None = None
|
|
@@ -178,7 +175,7 @@ class Enedis:
|
|
|
178
175
|
start, end = interval
|
|
179
176
|
try:
|
|
180
177
|
if raise_error is False:
|
|
181
|
-
response = await self.async_fetch_datas(
|
|
178
|
+
response = await self.async_fetch_datas(service, pdl, start, end)
|
|
182
179
|
except EnedisException as error:
|
|
183
180
|
raise_error = True
|
|
184
181
|
response = None
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"""Class for Enedis Authentication (http://www.myelectricaldata.fr)."""
|
|
2
2
|
|
|
3
3
|
import asyncio
|
|
4
|
+
from collections.abc import Mapping
|
|
4
5
|
import json
|
|
5
6
|
import logging
|
|
6
7
|
import socket
|
|
@@ -8,7 +9,6 @@ from typing import Any
|
|
|
8
9
|
|
|
9
10
|
from aiohttp import ClientError, ClientResponseError, ClientSession
|
|
10
11
|
|
|
11
|
-
from .const import TIMEOUT, URL
|
|
12
12
|
from .exceptions import (
|
|
13
13
|
EnedisException,
|
|
14
14
|
HttpRequestError,
|
|
@@ -17,14 +17,13 @@ from .exceptions import (
|
|
|
17
17
|
)
|
|
18
18
|
|
|
19
19
|
_LOGGER = logging.getLogger(__name__)
|
|
20
|
+
URL = "https://myelectricaldata.fr"
|
|
20
21
|
|
|
21
22
|
|
|
22
23
|
class EnedisAuth:
|
|
23
24
|
"""Class for Enedis Auth API."""
|
|
24
25
|
|
|
25
|
-
def __init__(
|
|
26
|
-
self, session: ClientSession, token: str, timeout: int = TIMEOUT
|
|
27
|
-
) -> None:
|
|
26
|
+
def __init__(self, session: ClientSession, token: str, timeout: int = 30) -> None:
|
|
28
27
|
"""Init."""
|
|
29
28
|
self.token = token
|
|
30
29
|
self.timeout = timeout
|
|
@@ -50,7 +49,8 @@ class EnedisAuth:
|
|
|
50
49
|
) from error
|
|
51
50
|
except ClientResponseError as error:
|
|
52
51
|
message = contents.decode("utf8")
|
|
53
|
-
|
|
52
|
+
headers: Mapping[str, str] = error.headers or {}
|
|
53
|
+
if "application/json" in headers.get("Content-Type", ""):
|
|
54
54
|
msg = json.loads(message)
|
|
55
55
|
if error.status == 409:
|
|
56
56
|
raise LimitReached(msg.get("detail", msg))
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"""Constants."""
|
|
2
|
+
|
|
3
|
+
from typing import Final
|
|
4
|
+
|
|
5
|
+
ATTR_CUM_PRICE = "cum_price"
|
|
6
|
+
ATTR_CUM_VALUE = "cum_value"
|
|
7
|
+
ATTR_END = "end"
|
|
8
|
+
ATTR_FN = "function"
|
|
9
|
+
ATTR_HPHC = "hphc"
|
|
10
|
+
ATTR_INTERVALS = "intervals"
|
|
11
|
+
ATTR_OFFPEAK = "offpeak"
|
|
12
|
+
ATTR_PRICE: Final = "price"
|
|
13
|
+
ATTR_PRICES = "prices"
|
|
14
|
+
ATTR_STANDARD = "standard"
|
|
15
|
+
ATTR_START = "start"
|
|
16
|
+
ATTR_TEMPO = "tempo"
|
|
17
|
+
TEMPO_DAYS = ("blue", "white", "red")
|
|
18
|
+
SUBSCRIPTIONS = (ATTR_STANDARD, ATTR_HPHC, ATTR_TEMPO)
|
|
19
|
+
DEFAULT_SUBSCRIPTION = ATTR_STANDARD
|
|
20
|
+
CONSUMPTION: Final = "consumption"
|
|
21
|
+
DAILY_CONSUM: Final = "daily_consumption"
|
|
22
|
+
DAILY_PROD: Final = "daily_production"
|
|
23
|
+
DETAIL_CONSUM: Final = "consumption_load_curve"
|
|
24
|
+
DETAIL_PROD: Final = "production_load_curve"
|
|
25
|
+
PRODUCTION: Final = "production"
|