bwt-api 0.5.1__tar.gz → 0.6.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.
- bwt_api-0.6.0/.devcontainer/devcontainer.json +7 -0
- {bwt_api-0.5.1/src/bwt_api.egg-info → bwt_api-0.6.0}/PKG-INFO +2 -1
- {bwt_api-0.5.1 → bwt_api-0.6.0}/pyproject.toml +4 -0
- {bwt_api-0.5.1 → bwt_api-0.6.0}/setup.cfg +1 -0
- {bwt_api-0.5.1 → bwt_api-0.6.0}/src/bwt_api/api.py +36 -1
- bwt_api-0.6.0/src/bwt_api/bwt.py +44 -0
- {bwt_api-0.5.1 → bwt_api-0.6.0}/src/bwt_api/skeleton.py +0 -1
- {bwt_api-0.5.1 → bwt_api-0.6.0/src/bwt_api.egg-info}/PKG-INFO +2 -1
- {bwt_api-0.5.1 → bwt_api-0.6.0}/src/bwt_api.egg-info/SOURCES.txt +4 -2
- {bwt_api-0.5.1 → bwt_api-0.6.0}/src/bwt_api.egg-info/requires.txt +1 -0
- bwt_api-0.6.0/tests/test_distinguish.py +64 -0
- bwt_api-0.5.1/tests/pytest.ini +0 -2
- {bwt_api-0.5.1 → bwt_api-0.6.0}/.coveragerc +0 -0
- {bwt_api-0.5.1 → bwt_api-0.6.0}/.github/workflows/python-package.yml +0 -0
- {bwt_api-0.5.1 → bwt_api-0.6.0}/.github/workflows/python-publish.yml +0 -0
- {bwt_api-0.5.1 → bwt_api-0.6.0}/.gitignore +0 -0
- {bwt_api-0.5.1 → bwt_api-0.6.0}/AUTHORS.rst +0 -0
- {bwt_api-0.5.1 → bwt_api-0.6.0}/CHANGELOG.rst +0 -0
- {bwt_api-0.5.1 → bwt_api-0.6.0}/CONTRIBUTING.rst +0 -0
- {bwt_api-0.5.1 → bwt_api-0.6.0}/LICENSE.txt +0 -0
- {bwt_api-0.5.1 → bwt_api-0.6.0}/README.rst +0 -0
- {bwt_api-0.5.1 → bwt_api-0.6.0}/setup.py +0 -0
- {bwt_api-0.5.1 → bwt_api-0.6.0}/src/bwt_api/__init__.py +0 -0
- {bwt_api-0.5.1 → bwt_api-0.6.0}/src/bwt_api/data.py +0 -0
- {bwt_api-0.5.1 → bwt_api-0.6.0}/src/bwt_api/error.py +0 -0
- {bwt_api-0.5.1 → bwt_api-0.6.0}/src/bwt_api/exception.py +0 -0
- {bwt_api-0.5.1 → bwt_api-0.6.0}/src/bwt_api.egg-info/dependency_links.txt +0 -0
- {bwt_api-0.5.1 → bwt_api-0.6.0}/src/bwt_api.egg-info/entry_points.txt +0 -0
- {bwt_api-0.5.1 → bwt_api-0.6.0}/src/bwt_api.egg-info/not-zip-safe +0 -0
- {bwt_api-0.5.1 → bwt_api-0.6.0}/src/bwt_api.egg-info/top_level.txt +0 -0
- {bwt_api-0.5.1 → bwt_api-0.6.0}/tests/conftest.py +0 -0
- {bwt_api-0.5.1 → bwt_api-0.6.0}/tests/test_api.py +0 -0
- {bwt_api-0.5.1 → bwt_api-0.6.0}/tox.ini +0 -0
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
|
|
2
|
+
// README at: https://github.com/devcontainers/templates/tree/main/src/python
|
|
3
|
+
{
|
|
4
|
+
"name": "Python 3",
|
|
5
|
+
"image": "mcr.microsoft.com/devcontainers/python:1-3.13-bullseye",
|
|
6
|
+
"postCreateCommand": "pip install --upgrade pip && pip install .[testing]"
|
|
7
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: bwt_api
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.6.0
|
|
4
4
|
Summary: Python API to access the local BWT Perla API.
|
|
5
5
|
Home-page: https://github.com/dkarv/bwt_api
|
|
6
6
|
Author: dkarv
|
|
@@ -22,6 +22,7 @@ Requires-Dist: flake8; extra == "testing"
|
|
|
22
22
|
Requires-Dist: setuptools; extra == "testing"
|
|
23
23
|
Requires-Dist: pytest; extra == "testing"
|
|
24
24
|
Requires-Dist: pytest-cov; extra == "testing"
|
|
25
|
+
Requires-Dist: pytest-asyncio; extra == "testing"
|
|
25
26
|
Requires-Dist: aioresponses; extra == "testing"
|
|
26
27
|
Dynamic: license-file
|
|
27
28
|
|
|
@@ -7,3 +7,7 @@ build-backend = "setuptools.build_meta"
|
|
|
7
7
|
# For smarter version schemes and other configuration options,
|
|
8
8
|
# check out https://github.com/pypa/setuptools_scm
|
|
9
9
|
version_scheme = "no-guess-dev"
|
|
10
|
+
|
|
11
|
+
[tool.pytest.ini_options]
|
|
12
|
+
pythonpath = ["src",]
|
|
13
|
+
asyncio_mode = "auto"
|
|
@@ -6,7 +6,6 @@ import aiohttp
|
|
|
6
6
|
import base64
|
|
7
7
|
import logging
|
|
8
8
|
from datetime import datetime
|
|
9
|
-
from zoneinfo import ZoneInfo
|
|
10
9
|
|
|
11
10
|
from bwt_api.error import BwtError
|
|
12
11
|
from bwt_api.exception import ApiException, ConnectException, WrongCodeException
|
|
@@ -135,6 +134,42 @@ class BwtApi:
|
|
|
135
134
|
keys = [f"Month{month:02}_l" for month in range(1, 13)]
|
|
136
135
|
return YearlyResponse(list(map(lambda k: raw[k], keys)))
|
|
137
136
|
|
|
137
|
+
|
|
138
|
+
class BwtSilkApi:
|
|
139
|
+
"""BWT Silk Api."""
|
|
140
|
+
_session: aiohttp.ClientSession
|
|
141
|
+
_host: str
|
|
142
|
+
|
|
143
|
+
def __init__(self, host):
|
|
144
|
+
self._host = host
|
|
145
|
+
self._session = aiohttp.ClientSession()
|
|
146
|
+
|
|
147
|
+
async def __aenter__(self):
|
|
148
|
+
return self
|
|
149
|
+
|
|
150
|
+
async def __aexit__(self, *err):
|
|
151
|
+
await self.close()
|
|
152
|
+
|
|
153
|
+
async def close(self):
|
|
154
|
+
await self._session.close()
|
|
155
|
+
|
|
156
|
+
async def get_registers(self) -> list[int]:
|
|
157
|
+
"""Internal method to fetch json from the endpoint and handle general errors."""
|
|
158
|
+
try:
|
|
159
|
+
async with self._session.get(f"http://{self._host}:80/silk/registers") as response:
|
|
160
|
+
_logger.debug(f"Response status: {response.status}, content-type: {response.headers['content-type']}")
|
|
161
|
+
if (response.status == 200):
|
|
162
|
+
json = await response.json(content_type=None)
|
|
163
|
+
_logger.debug(f"Raw response: {json}")
|
|
164
|
+
return json["params"]
|
|
165
|
+
else:
|
|
166
|
+
text = await response.text()
|
|
167
|
+
_logger.warning(f"Unknown response with status {response.status}: {text}")
|
|
168
|
+
raise ApiException(f"Unknown response: {text}")
|
|
169
|
+
except aiohttp.ClientConnectorError as e:
|
|
170
|
+
raise ConnectException from e
|
|
171
|
+
|
|
172
|
+
|
|
138
173
|
def treated_to_blended(treated: int, hardness_in: int, hardness_out: int) -> float:
|
|
139
174
|
if (hardness_in == 0 | hardness_in == hardness_out):
|
|
140
175
|
return treated
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"""The BWT model check."""
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
from enum import Enum
|
|
5
|
+
import aiohttp
|
|
6
|
+
import logging
|
|
7
|
+
|
|
8
|
+
from bwt_api.exception import ConnectException
|
|
9
|
+
|
|
10
|
+
_logger = logging.getLogger(__name__)
|
|
11
|
+
|
|
12
|
+
class BwtModel(Enum):
|
|
13
|
+
"""Enum for BWT models."""
|
|
14
|
+
PERLA_LOCAL_API = 1
|
|
15
|
+
PERLA_SILK = 2
|
|
16
|
+
|
|
17
|
+
async def determine_bwt_model(host: str) -> BwtModel:
|
|
18
|
+
"""Determine the BWT model based on the api response."""
|
|
19
|
+
|
|
20
|
+
_logger.debug(f"Determining BWT model for host {host}")
|
|
21
|
+
timeout = aiohttp.ClientTimeout(total=3)
|
|
22
|
+
# Try :8080/api/GetCurrentData
|
|
23
|
+
try:
|
|
24
|
+
async with aiohttp.ClientSession() as session:
|
|
25
|
+
async with session.get(f"http://{host}:8080/api", timeout=timeout) as response:
|
|
26
|
+
res = await response.text()
|
|
27
|
+
_logger.debug(f"Response from {host}:8080/api: {response.status} - {res}")
|
|
28
|
+
if response.status == 404 and res == "Not Found":
|
|
29
|
+
return BwtModel.PERLA_LOCAL_API
|
|
30
|
+
except Exception:
|
|
31
|
+
pass
|
|
32
|
+
|
|
33
|
+
# Try :80/status
|
|
34
|
+
try:
|
|
35
|
+
async with aiohttp.ClientSession() as session:
|
|
36
|
+
async with session.get(f"http://{host}:80/silk/registers", timeout=timeout) as response:
|
|
37
|
+
res = await response.text()
|
|
38
|
+
_logger.debug(f"Response from {host}:80/silk/registers: {response.status} - {res}")
|
|
39
|
+
if response.status == 200 and res.startswith("""{"params":["""):
|
|
40
|
+
return BwtModel.PERLA_SILK
|
|
41
|
+
except Exception:
|
|
42
|
+
pass
|
|
43
|
+
|
|
44
|
+
raise ConnectException(f"Could not determine BWT model for host {host}. Please check the connection or the host address.")
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: bwt_api
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.6.0
|
|
4
4
|
Summary: Python API to access the local BWT Perla API.
|
|
5
5
|
Home-page: https://github.com/dkarv/bwt_api
|
|
6
6
|
Author: dkarv
|
|
@@ -22,6 +22,7 @@ Requires-Dist: flake8; extra == "testing"
|
|
|
22
22
|
Requires-Dist: setuptools; extra == "testing"
|
|
23
23
|
Requires-Dist: pytest; extra == "testing"
|
|
24
24
|
Requires-Dist: pytest-cov; extra == "testing"
|
|
25
|
+
Requires-Dist: pytest-asyncio; extra == "testing"
|
|
25
26
|
Requires-Dist: aioresponses; extra == "testing"
|
|
26
27
|
Dynamic: license-file
|
|
27
28
|
|
|
@@ -9,10 +9,12 @@ pyproject.toml
|
|
|
9
9
|
setup.cfg
|
|
10
10
|
setup.py
|
|
11
11
|
tox.ini
|
|
12
|
+
.devcontainer/devcontainer.json
|
|
12
13
|
.github/workflows/python-package.yml
|
|
13
14
|
.github/workflows/python-publish.yml
|
|
14
15
|
src/bwt_api/__init__.py
|
|
15
16
|
src/bwt_api/api.py
|
|
17
|
+
src/bwt_api/bwt.py
|
|
16
18
|
src/bwt_api/data.py
|
|
17
19
|
src/bwt_api/error.py
|
|
18
20
|
src/bwt_api/exception.py
|
|
@@ -25,5 +27,5 @@ src/bwt_api.egg-info/not-zip-safe
|
|
|
25
27
|
src/bwt_api.egg-info/requires.txt
|
|
26
28
|
src/bwt_api.egg-info/top_level.txt
|
|
27
29
|
tests/conftest.py
|
|
28
|
-
tests/
|
|
29
|
-
tests/
|
|
30
|
+
tests/test_api.py
|
|
31
|
+
tests/test_distinguish.py
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
from datetime import datetime
|
|
2
|
+
from zoneinfo import ZoneInfo
|
|
3
|
+
import pytest
|
|
4
|
+
|
|
5
|
+
from bwt_api.api import BwtApi, treated_to_blended
|
|
6
|
+
from bwt_api.bwt import BwtModel, determine_bwt_model
|
|
7
|
+
from bwt_api.error import BwtError
|
|
8
|
+
from bwt_api.data import CurrentResponse, Hardness, BwtStatus
|
|
9
|
+
|
|
10
|
+
from aioresponses import aioresponses
|
|
11
|
+
|
|
12
|
+
from bwt_api.exception import ApiException, ConnectException, WrongCodeException
|
|
13
|
+
|
|
14
|
+
new_json = """
|
|
15
|
+
{
|
|
16
|
+
"ActiveErrorIDs" : "5,32,34",
|
|
17
|
+
"BlendedWaterSinceSetup_l" : 318383,
|
|
18
|
+
"CapacityColumn1_ml_dH" : 5485275,
|
|
19
|
+
"CapacityColumn2_ml_dH" : 3833994,
|
|
20
|
+
"CurrentFlowrate_l_h" : 0,
|
|
21
|
+
"DosingSinceSetup_ml" : 0,
|
|
22
|
+
"FirmwareVersion" : "2.0207",
|
|
23
|
+
"HardnessIN_CaCO3" : 374,
|
|
24
|
+
"HardnessIN_dH" : 21,
|
|
25
|
+
"HardnessIN_fH" : 37,
|
|
26
|
+
"HardnessIN_mmol_l" : 4,
|
|
27
|
+
"HardnessOUT_CaCO3" : 71,
|
|
28
|
+
"HardnessOUT_dH" : 4,
|
|
29
|
+
"HardnessOUT_fH" : 7,
|
|
30
|
+
"HardnessOUT_mmol_l" : 1,
|
|
31
|
+
"HolidayModeStartTime" : 0,
|
|
32
|
+
"LastRegenerationColumn1" : "2023-11-16 04:42:15",
|
|
33
|
+
"LastRegenerationColumn2" : "2023-11-15 04:41:48",
|
|
34
|
+
"LastServiceCustomer" : "2023-05-18 10:51:07",
|
|
35
|
+
"LastServiceTechnican" : "2021-01-25 13:14:06",
|
|
36
|
+
"OutOfService" : 0,
|
|
37
|
+
"RegenerationCountSinceSetup" : 1505,
|
|
38
|
+
"RegenerationCounterColumn1" : 754,
|
|
39
|
+
"RegenerationCounterColumn2" : 751,
|
|
40
|
+
"RegenerativLevel" : 20,
|
|
41
|
+
"RegenerativRemainingDays" : 26,
|
|
42
|
+
"RegenerativSinceSetup_g" : 245846,
|
|
43
|
+
"ShowError" : 2,
|
|
44
|
+
"WaterSinceSetup_l" : 261633,
|
|
45
|
+
"WaterTreatedCurrentDay_l" : 181,
|
|
46
|
+
"WaterTreatedCurrentMonth_l" : 3137,
|
|
47
|
+
"WaterTreatedCurrentYear_l" : 80700
|
|
48
|
+
}
|
|
49
|
+
"""
|
|
50
|
+
|
|
51
|
+
silk_json = """{"params":[0,-1,18,23,285,29,16,2,0,9,8,1,8,4,296,158,0,52,2138,9,40,0,100,2275,11,20,50,1,1,0,160,141,20,0,678,1,-1,-1,6,1,1,15,355,-1,-1,-1,-1,0]}"""
|
|
52
|
+
|
|
53
|
+
async def test_local_api():
|
|
54
|
+
with aioresponses() as mocked:
|
|
55
|
+
mocked.get("http://host:8080/api", status=404, body="Not Found")
|
|
56
|
+
result = await determine_bwt_model("host")
|
|
57
|
+
assert result == BwtModel.PERLA_LOCAL_API
|
|
58
|
+
|
|
59
|
+
async def test_silk():
|
|
60
|
+
with aioresponses() as mocked:
|
|
61
|
+
mocked.get("http://host:8080/api", status=404, body="Some other webservice")
|
|
62
|
+
mocked.get("http://host:80/silk/registers", status=200, body=silk_json)
|
|
63
|
+
result = await determine_bwt_model("host")
|
|
64
|
+
assert result == BwtModel.PERLA_SILK
|
bwt_api-0.5.1/tests/pytest.ini
DELETED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|