PyHolfuy 0.1__tar.gz → 0.2__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.
- {pyholfuy-0.1/pyholfuy.egg-info → pyholfuy-0.2}/PKG-INFO +1 -9
- {pyholfuy-0.1 → pyholfuy-0.2}/holfuy/__init__.py +10 -16
- {pyholfuy-0.1 → pyholfuy-0.2}/holfuy/const.py +1 -1
- pyholfuy-0.2/holfuy/test_holfuy.py +156 -0
- {pyholfuy-0.1 → pyholfuy-0.2/pyholfuy.egg-info}/PKG-INFO +1 -9
- {pyholfuy-0.1 → pyholfuy-0.2}/pyholfuy.egg-info/SOURCES.txt +1 -0
- pyholfuy-0.2/pyholfuy.egg-info/requires.txt +8 -0
- {pyholfuy-0.1 → pyholfuy-0.2}/pyproject.toml +1 -14
- pyholfuy-0.1/pyholfuy.egg-info/requires.txt +0 -16
- {pyholfuy-0.1 → pyholfuy-0.2}/LICENSE +0 -0
- {pyholfuy-0.1 → pyholfuy-0.2}/MANIFEST.in +0 -0
- {pyholfuy-0.1 → pyholfuy-0.2}/README.md +0 -0
- {pyholfuy-0.1 → pyholfuy-0.2}/pyholfuy.egg-info/dependency_links.txt +0 -0
- {pyholfuy-0.1 → pyholfuy-0.2}/pyholfuy.egg-info/top_level.txt +0 -0
- {pyholfuy-0.1 → pyholfuy-0.2}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pyholfuy
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.2
|
|
4
4
|
Summary: A Python library for interacting with Holfuy weather stations.
|
|
5
5
|
Author-email: Håvard Dagenborg <haavardj@dagenborg.net>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -16,15 +16,7 @@ Provides-Extra: test
|
|
|
16
16
|
Requires-Dist: aioresponses==0.7.8; extra == "test"
|
|
17
17
|
Requires-Dist: coverage==7.8.0; extra == "test"
|
|
18
18
|
Requires-Dist: mypy==1.15.0; extra == "test"
|
|
19
|
-
Requires-Dist: pytest-asyncio==0.26.0; extra == "test"
|
|
20
|
-
Requires-Dist: pytest-cov==6.1.1; extra == "test"
|
|
21
|
-
Requires-Dist: pytest-error-for-skips==2.0.2; extra == "test"
|
|
22
|
-
Requires-Dist: pytest-timeout==2.3.1; extra == "test"
|
|
23
|
-
Requires-Dist: pytest==8.3.5; extra == "test"
|
|
24
|
-
Requires-Dist: ruff==0.11.7; extra == "test"
|
|
25
|
-
Requires-Dist: syrupy==4.9.1; extra == "test"
|
|
26
19
|
Provides-Extra: dev
|
|
27
|
-
Requires-Dist: pre-commit==4.2.0; extra == "dev"
|
|
28
20
|
Dynamic: license-file
|
|
29
21
|
|
|
30
22
|

|
|
@@ -6,9 +6,10 @@ import logging
|
|
|
6
6
|
from typing import Any
|
|
7
7
|
|
|
8
8
|
import aiohttp
|
|
9
|
+
from aiohttp import ClientSession
|
|
9
10
|
|
|
10
11
|
from .const import (
|
|
11
|
-
|
|
12
|
+
CONF_TEMPERATURE_UNIT_CELSIUS,
|
|
12
13
|
CONF_WIND_SPEED_UNIT_MS,
|
|
13
14
|
CONF_AVERAGING_NEWEST,
|
|
14
15
|
CONF_MODE_JSON,
|
|
@@ -45,10 +46,10 @@ class HolfuyService:
|
|
|
45
46
|
def __init__(
|
|
46
47
|
self,
|
|
47
48
|
api_key: str,
|
|
48
|
-
|
|
49
|
-
temperature_unit=
|
|
50
|
-
wind_speed_unit=CONF_WIND_SPEED_UNIT_MS,
|
|
51
|
-
timestamps_in_utc=False,
|
|
49
|
+
session: ClientSession,
|
|
50
|
+
temperature_unit:str=CONF_TEMPERATURE_UNIT_CELSIUS,
|
|
51
|
+
wind_speed_unit:str=CONF_WIND_SPEED_UNIT_MS,
|
|
52
|
+
timestamps_in_utc:bool=False,
|
|
52
53
|
) -> None:
|
|
53
54
|
"""Initialize the Weather object."""
|
|
54
55
|
|
|
@@ -57,16 +58,8 @@ class HolfuyService:
|
|
|
57
58
|
self._wind_speed_unit = wind_speed_unit
|
|
58
59
|
self._temperature_unit = temperature_unit
|
|
59
60
|
self._timestamps_in_utc = timestamps_in_utc
|
|
61
|
+
self._session = session
|
|
60
62
|
|
|
61
|
-
if websession is None:
|
|
62
|
-
|
|
63
|
-
async def _create_session():
|
|
64
|
-
return aiohttp.ClientSession()
|
|
65
|
-
|
|
66
|
-
loop = asyncio.get_event_loop()
|
|
67
|
-
self._websession = loop.run_until_complete(_create_session())
|
|
68
|
-
else:
|
|
69
|
-
self._websession = websession
|
|
70
63
|
|
|
71
64
|
async def fetch_data(
|
|
72
65
|
self,
|
|
@@ -104,8 +97,9 @@ class HolfuyService:
|
|
|
104
97
|
params["s"] = STATIONS_ALL
|
|
105
98
|
|
|
106
99
|
try:
|
|
100
|
+
|
|
107
101
|
async with asyncio.timeout(TIMEOUT):
|
|
108
|
-
resp = await self.
|
|
102
|
+
resp = await self._session.get(self._api_url, params=params)
|
|
109
103
|
|
|
110
104
|
if resp.status >= 400:
|
|
111
105
|
_LOGGER.error("%s returned %s", self._api_url, resp.status)
|
|
@@ -117,7 +111,7 @@ class HolfuyService:
|
|
|
117
111
|
# measurements objects. Make data consistent for all request types before it
|
|
118
112
|
# is returned.
|
|
119
113
|
if stations and len(stations) == 1:
|
|
120
|
-
result = {"measurements": result}
|
|
114
|
+
result = {"measurements": [result]}
|
|
121
115
|
|
|
122
116
|
return result
|
|
123
117
|
|
|
@@ -11,7 +11,7 @@ CONF_WIND_SPEED_UNIT_KMH = "km/h"
|
|
|
11
11
|
CONF_WIND_SPEED_UNIT_MS = "m/s"
|
|
12
12
|
CONF_WIND_SPEED_UNIT_MPH = "mph"
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
CONF_TEMPERATURE_UNIT_CELSIUS = "Celsius"
|
|
15
15
|
CONF_TEMPERATURE_UNIT_FAHRENHEIT = "Fahrenheit"
|
|
16
16
|
|
|
17
17
|
CONF_OPTION_BATT = "batt"
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
from unittest import IsolatedAsyncioTestCase, mock
|
|
3
|
+
from unittest.mock import AsyncMock, patch
|
|
4
|
+
import json
|
|
5
|
+
|
|
6
|
+
import aiohttp
|
|
7
|
+
|
|
8
|
+
RESP_142 = json.loads("""{"stationId":142,"stationName":"THPK Ersfjord","location":{"latitude":"69.70017",
|
|
9
|
+
"longitude":"18.63842","altitude":130},"dateTime":"2025-05-19 15:45:00","wind":{"speed":9.4,"gust":13.3,"min":0,
|
|
10
|
+
"unit":"m/s","direction":245},"battery":4.15,"daily":{"max_temp":0,"min_temp":0},"temperature":0}""")
|
|
11
|
+
|
|
12
|
+
RESP_ALL = json.loads("""{"measurements":[{"stationId":142,"stationName":"THPK Ersfjord","location":{"latitude":"69.70017",
|
|
13
|
+
"longitude":"18.63842","altitude":130},"dateTime":"2025-05-19 15:45:00","wind":{"speed":9.4,"gust":13.3,"min":0,
|
|
14
|
+
"unit":"m/s","direction":245},"battery":4.15,"daily":{"max_temp":0,"min_temp":0},"temperature":0},
|
|
15
|
+
{"stationId":207,"stationName":"THPK Finnvikdalen","location":{"latitude":"69.76117",
|
|
16
|
+
"longitude":"18.85657","altitude":270},"dateTime":"2025-05-19 15:45:00",
|
|
17
|
+
"wind":{"speed":10,"gust":13.6,"min":0,"unit":"m/s","direction":339},"battery":4.14,
|
|
18
|
+
"daily":{"max_temp":7.5,"min_temp":4.5},"temperature":4.7},{"stationId":299,"stationName":"THPK Fjellheisen",
|
|
19
|
+
"location":{"latitude":"69.63116","longitude":"18.99377","altitude":420},"dateTime":"2025-05-19 15:45:00",
|
|
20
|
+
"wind":{"speed":7.8,"gust":10.3,"min":0,"unit":"m/s","direction":256},"battery":4.14,
|
|
21
|
+
"daily":{"max_temp":5.7,"min_temp":0},"temperature":3.6}]}""")
|
|
22
|
+
|
|
23
|
+
RESP_AUTHERROR=json.loads("""
|
|
24
|
+
{"measurements":[{"stationId":105,"error":"Sorry, you don't have access for this station.","errorCode":"no_access"},
|
|
25
|
+
{"stationId":106,"error":"Sorry, you don't have access for this station.","errorCode":"no_access"}]}""")
|
|
26
|
+
|
|
27
|
+
from holfuy import HolfuyService
|
|
28
|
+
|
|
29
|
+
from holfuy.const import (
|
|
30
|
+
CONF_TEMPERATURE_UNIT_CELSIUS,
|
|
31
|
+
CONF_WIND_SPEED_UNIT_MS,
|
|
32
|
+
CONF_AVERAGING_NEWEST,
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class TestHolfuyService(IsolatedAsyncioTestCase):
|
|
37
|
+
def setUp(self):
|
|
38
|
+
"""Set up test cases."""
|
|
39
|
+
self.session = AsyncMock(spec=aiohttp.ClientSession)
|
|
40
|
+
self.api = HolfuyService(
|
|
41
|
+
"test_api_key",
|
|
42
|
+
self.session,
|
|
43
|
+
CONF_TEMPERATURE_UNIT_CELSIUS,
|
|
44
|
+
CONF_WIND_SPEED_UNIT_MS,
|
|
45
|
+
False,
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
async def test_fetch_data_single_station(self):
|
|
49
|
+
"""Test fetching data for a single station."""
|
|
50
|
+
mock_response = RESP_142
|
|
51
|
+
|
|
52
|
+
mock_resp = AsyncMock()
|
|
53
|
+
mock_resp.status = 200
|
|
54
|
+
mock_resp.json = AsyncMock(return_value=mock_response)
|
|
55
|
+
|
|
56
|
+
self.session.get = AsyncMock(return_value=mock_resp)
|
|
57
|
+
|
|
58
|
+
result = await self.api.fetch_data(["142"])
|
|
59
|
+
|
|
60
|
+
expected_params = {
|
|
61
|
+
"pw": "test_api_key",
|
|
62
|
+
"m": "JSON",
|
|
63
|
+
"tu": CONF_TEMPERATURE_UNIT_CELSIUS,
|
|
64
|
+
"su": CONF_WIND_SPEED_UNIT_MS,
|
|
65
|
+
"avg": CONF_AVERAGING_NEWEST,
|
|
66
|
+
"s": "142",
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
self.session.get.assert_called_once_with(
|
|
70
|
+
"http://api.holfuy.com/live/",
|
|
71
|
+
params=expected_params
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
self.assertEqual(result["measurements"][0]["stationId"], 142)
|
|
75
|
+
|
|
76
|
+
async def test_fetch_data_all_stations(self):
|
|
77
|
+
"""Test fetching data for multiple stations."""
|
|
78
|
+
mock_response = RESP_ALL
|
|
79
|
+
|
|
80
|
+
mock_resp = AsyncMock()
|
|
81
|
+
mock_resp.status = 200
|
|
82
|
+
mock_resp.json = AsyncMock(return_value=mock_response)
|
|
83
|
+
self.session.get = AsyncMock(return_value= mock_resp)
|
|
84
|
+
|
|
85
|
+
result = await self.api.fetch_data(None)
|
|
86
|
+
|
|
87
|
+
expected_params = {
|
|
88
|
+
"pw": "test_api_key",
|
|
89
|
+
"m": "JSON",
|
|
90
|
+
"tu": CONF_TEMPERATURE_UNIT_CELSIUS,
|
|
91
|
+
"su": CONF_WIND_SPEED_UNIT_MS,
|
|
92
|
+
"avg": CONF_AVERAGING_NEWEST,
|
|
93
|
+
"s": "all",
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
self.session.get.assert_called_once_with(
|
|
97
|
+
"http://api.holfuy.com/live/",
|
|
98
|
+
params=expected_params
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
self.assertEqual(result, mock_response)
|
|
102
|
+
|
|
103
|
+
async def test_fetch_data_error_response(self):
|
|
104
|
+
"""Test handling of error responses."""
|
|
105
|
+
mock_resp = AsyncMock()
|
|
106
|
+
mock_resp.status = 404
|
|
107
|
+
|
|
108
|
+
self.session.get = AsyncMock(return_value=mock_resp)
|
|
109
|
+
|
|
110
|
+
result = await self.api.fetch_data(None)
|
|
111
|
+
|
|
112
|
+
self.assertIsNone(result)
|
|
113
|
+
|
|
114
|
+
async def test_fetch_data_invalid_access_token(self):
|
|
115
|
+
"""Test handling of error responses."""
|
|
116
|
+
mock_resp = AsyncMock()
|
|
117
|
+
mock_resp.status = 200
|
|
118
|
+
mock_response = RESP_AUTHERROR
|
|
119
|
+
|
|
120
|
+
mock_resp.json = AsyncMock(return_value=mock_response)
|
|
121
|
+
|
|
122
|
+
self.session.get = AsyncMock(return_value=mock_resp)
|
|
123
|
+
|
|
124
|
+
result = await self.api.fetch_data(["105","106"])
|
|
125
|
+
|
|
126
|
+
expected_params = {
|
|
127
|
+
"pw": "test_api_key",
|
|
128
|
+
"m": "JSON",
|
|
129
|
+
"tu": CONF_TEMPERATURE_UNIT_CELSIUS,
|
|
130
|
+
"su": CONF_WIND_SPEED_UNIT_MS,
|
|
131
|
+
"avg": CONF_AVERAGING_NEWEST,
|
|
132
|
+
"s": "105,106",
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
self.session.get.assert_called_once_with(
|
|
136
|
+
"http://api.holfuy.com/live/",
|
|
137
|
+
params=expected_params
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
self.assertEqual(result["measurements"][0]["stationId"], 105)
|
|
141
|
+
|
|
142
|
+
async def test_fetch_data_timeout(self):
|
|
143
|
+
"""Test handling of timeout errors."""
|
|
144
|
+
self.session.get = AsyncMock(side_effect=asyncio.TimeoutError)
|
|
145
|
+
|
|
146
|
+
result = await self.api.fetch_data(None)
|
|
147
|
+
|
|
148
|
+
self.assertIsNone(result)
|
|
149
|
+
|
|
150
|
+
async def test_fetch_data_client_error(self):
|
|
151
|
+
"""Test handling of client errors."""
|
|
152
|
+
self.session.get = AsyncMock(side_effect=aiohttp.ClientError)
|
|
153
|
+
|
|
154
|
+
result = await self.api.fetch_data(None)
|
|
155
|
+
|
|
156
|
+
self.assertIsNone(result)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pyholfuy
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.2
|
|
4
4
|
Summary: A Python library for interacting with Holfuy weather stations.
|
|
5
5
|
Author-email: Håvard Dagenborg <haavardj@dagenborg.net>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -16,15 +16,7 @@ Provides-Extra: test
|
|
|
16
16
|
Requires-Dist: aioresponses==0.7.8; extra == "test"
|
|
17
17
|
Requires-Dist: coverage==7.8.0; extra == "test"
|
|
18
18
|
Requires-Dist: mypy==1.15.0; extra == "test"
|
|
19
|
-
Requires-Dist: pytest-asyncio==0.26.0; extra == "test"
|
|
20
|
-
Requires-Dist: pytest-cov==6.1.1; extra == "test"
|
|
21
|
-
Requires-Dist: pytest-error-for-skips==2.0.2; extra == "test"
|
|
22
|
-
Requires-Dist: pytest-timeout==2.3.1; extra == "test"
|
|
23
|
-
Requires-Dist: pytest==8.3.5; extra == "test"
|
|
24
|
-
Requires-Dist: ruff==0.11.7; extra == "test"
|
|
25
|
-
Requires-Dist: syrupy==4.9.1; extra == "test"
|
|
26
19
|
Provides-Extra: dev
|
|
27
|
-
Requires-Dist: pre-commit==4.2.0; extra == "dev"
|
|
28
20
|
Dynamic: license-file
|
|
29
21
|
|
|
30
22
|

|
|
@@ -6,7 +6,7 @@ build-backend = "setuptools.build_meta"
|
|
|
6
6
|
|
|
7
7
|
[project]
|
|
8
8
|
name = "pyholfuy"
|
|
9
|
-
version = "0.
|
|
9
|
+
version = "0.2"
|
|
10
10
|
description = "A Python library for interacting with Holfuy weather stations."
|
|
11
11
|
authors = [{name="Håvard Dagenborg", email="haavardj@dagenborg.net"}]
|
|
12
12
|
license = "MIT"
|
|
@@ -29,24 +29,11 @@ test = [
|
|
|
29
29
|
"aioresponses==0.7.8",
|
|
30
30
|
"coverage==7.8.0",
|
|
31
31
|
"mypy==1.15.0",
|
|
32
|
-
"pytest-asyncio==0.26.0",
|
|
33
|
-
"pytest-cov==6.1.1",
|
|
34
|
-
"pytest-error-for-skips==2.0.2",
|
|
35
|
-
"pytest-timeout==2.3.1",
|
|
36
|
-
"pytest==8.3.5",
|
|
37
|
-
"ruff==0.11.7",
|
|
38
|
-
"syrupy==4.9.1",
|
|
39
32
|
]
|
|
40
33
|
dev = [
|
|
41
|
-
"pre-commit==4.2.0",
|
|
42
34
|
]
|
|
43
35
|
|
|
44
|
-
[tool.ruff]
|
|
45
|
-
line-length = 88
|
|
46
|
-
indent-width = 4
|
|
47
|
-
select = ["E", "F", "W", "C", "N", "Q"]
|
|
48
36
|
|
|
49
37
|
[tool.pylint]
|
|
50
38
|
max-line-length = 88
|
|
51
39
|
disable = ["C0114", "C0115", "C0116"]
|
|
52
|
-
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
aiohttp>=3.9.4
|
|
2
|
-
|
|
3
|
-
[dev]
|
|
4
|
-
pre-commit==4.2.0
|
|
5
|
-
|
|
6
|
-
[test]
|
|
7
|
-
aioresponses==0.7.8
|
|
8
|
-
coverage==7.8.0
|
|
9
|
-
mypy==1.15.0
|
|
10
|
-
pytest-asyncio==0.26.0
|
|
11
|
-
pytest-cov==6.1.1
|
|
12
|
-
pytest-error-for-skips==2.0.2
|
|
13
|
-
pytest-timeout==2.3.1
|
|
14
|
-
pytest==8.3.5
|
|
15
|
-
ruff==0.11.7
|
|
16
|
-
syrupy==4.9.1
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|