blebox-uniapi 2.2.1__tar.gz → 2.2.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.
- {blebox_uniapi-2.2.1 → blebox_uniapi-2.2.2}/HISTORY.rst +5 -0
- {blebox_uniapi-2.2.1 → blebox_uniapi-2.2.2}/PKG-INFO +6 -2
- {blebox_uniapi-2.2.1 → blebox_uniapi-2.2.2}/blebox_uniapi/__init__.py +1 -1
- {blebox_uniapi-2.2.1 → blebox_uniapi-2.2.2}/blebox_uniapi/sensor.py +7 -1
- {blebox_uniapi-2.2.1 → blebox_uniapi-2.2.2}/blebox_uniapi.egg-info/PKG-INFO +6 -2
- {blebox_uniapi-2.2.1 → blebox_uniapi-2.2.2}/blebox_uniapi.egg-info/SOURCES.txt +2 -0
- {blebox_uniapi-2.2.1 → blebox_uniapi-2.2.2}/setup.cfg +5 -5
- {blebox_uniapi-2.2.1 → blebox_uniapi-2.2.2}/setup.py +1 -2
- blebox_uniapi-2.2.2/tests/__init__.py +1 -0
- blebox_uniapi-2.2.2/tests/conftest.py +331 -0
- {blebox_uniapi-2.2.1 → blebox_uniapi-2.2.2}/CONTRIBUTING.rst +0 -0
- {blebox_uniapi-2.2.1 → blebox_uniapi-2.2.2}/LICENSE +0 -0
- {blebox_uniapi-2.2.1 → blebox_uniapi-2.2.2}/MANIFEST.in +0 -0
- {blebox_uniapi-2.2.1 → blebox_uniapi-2.2.2}/README.rst +0 -0
- {blebox_uniapi-2.2.1 → blebox_uniapi-2.2.2}/blebox_uniapi/binary_sensor.py +0 -0
- {blebox_uniapi-2.2.1 → blebox_uniapi-2.2.2}/blebox_uniapi/box.py +0 -0
- {blebox_uniapi-2.2.1 → blebox_uniapi-2.2.2}/blebox_uniapi/box_types.py +0 -0
- {blebox_uniapi-2.2.1 → blebox_uniapi-2.2.2}/blebox_uniapi/button.py +0 -0
- {blebox_uniapi-2.2.1 → blebox_uniapi-2.2.2}/blebox_uniapi/climate.py +0 -0
- {blebox_uniapi-2.2.1 → blebox_uniapi-2.2.2}/blebox_uniapi/cover.py +0 -0
- {blebox_uniapi-2.2.1 → blebox_uniapi-2.2.2}/blebox_uniapi/error.py +0 -0
- {blebox_uniapi-2.2.1 → blebox_uniapi-2.2.2}/blebox_uniapi/feature.py +0 -0
- {blebox_uniapi-2.2.1 → blebox_uniapi-2.2.2}/blebox_uniapi/light.py +0 -0
- {blebox_uniapi-2.2.1 → blebox_uniapi-2.2.2}/blebox_uniapi/session.py +0 -0
- {blebox_uniapi-2.2.1 → blebox_uniapi-2.2.2}/blebox_uniapi/switch.py +0 -0
- {blebox_uniapi-2.2.1 → blebox_uniapi-2.2.2}/blebox_uniapi.egg-info/dependency_links.txt +0 -0
- {blebox_uniapi-2.2.1 → blebox_uniapi-2.2.2}/blebox_uniapi.egg-info/not-zip-safe +0 -0
- {blebox_uniapi-2.2.1 → blebox_uniapi-2.2.2}/blebox_uniapi.egg-info/requires.txt +0 -0
- {blebox_uniapi-2.2.1 → blebox_uniapi-2.2.2}/blebox_uniapi.egg-info/top_level.txt +0 -0
- {blebox_uniapi-2.2.1 → blebox_uniapi-2.2.2}/docs/Makefile +0 -0
- {blebox_uniapi-2.2.1 → blebox_uniapi-2.2.2}/docs/authors.rst +0 -0
- {blebox_uniapi-2.2.1 → blebox_uniapi-2.2.2}/docs/conf.py +0 -0
- {blebox_uniapi-2.2.1 → blebox_uniapi-2.2.2}/docs/contributing.rst +0 -0
- {blebox_uniapi-2.2.1 → blebox_uniapi-2.2.2}/docs/history.rst +0 -0
- {blebox_uniapi-2.2.1 → blebox_uniapi-2.2.2}/docs/index.rst +0 -0
- {blebox_uniapi-2.2.1 → blebox_uniapi-2.2.2}/docs/installation.rst +0 -0
- {blebox_uniapi-2.2.1 → blebox_uniapi-2.2.2}/docs/make.bat +0 -0
- {blebox_uniapi-2.2.1 → blebox_uniapi-2.2.2}/docs/readme.rst +0 -0
- {blebox_uniapi-2.2.1 → blebox_uniapi-2.2.2}/docs/usage.rst +0 -0
- {blebox_uniapi-2.2.1 → blebox_uniapi-2.2.2}/tests/test_box.py +0 -0
- {blebox_uniapi-2.2.1 → blebox_uniapi-2.2.2}/tests/test_box_types.py +0 -0
- {blebox_uniapi-2.2.1 → blebox_uniapi-2.2.2}/tests/test_button.py +0 -0
- {blebox_uniapi-2.2.1 → blebox_uniapi-2.2.2}/tests/test_climate.py +0 -0
- {blebox_uniapi-2.2.1 → blebox_uniapi-2.2.2}/tests/test_cover.py +0 -0
- {blebox_uniapi-2.2.1 → blebox_uniapi-2.2.2}/tests/test_error.py +0 -0
- {blebox_uniapi-2.2.1 → blebox_uniapi-2.2.2}/tests/test_light.py +0 -0
- {blebox_uniapi-2.2.1 → blebox_uniapi-2.2.2}/tests/test_light_unit.py +0 -0
- {blebox_uniapi-2.2.1 → blebox_uniapi-2.2.2}/tests/test_sensor.py +0 -0
- {blebox_uniapi-2.2.1 → blebox_uniapi-2.2.2}/tests/test_session.py +0 -0
- {blebox_uniapi-2.2.1 → blebox_uniapi-2.2.2}/tests/test_switch.py +0 -0
- {blebox_uniapi-2.2.1 → blebox_uniapi-2.2.2}/tests/test_unknown.py +0 -0
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
=======
|
|
2
2
|
History
|
|
3
3
|
=======
|
|
4
|
+
2.2.2 (2024-02-07)
|
|
5
|
+
------------------
|
|
6
|
+
* fixed wind reading units to get proper raw m/s value (division by 10, see PR #150)
|
|
7
|
+
|
|
8
|
+
|
|
4
9
|
2.2.1 (2024-01-26)
|
|
5
10
|
------------------
|
|
6
11
|
* fixed support for power measurement capabilities of switchBox and switchBoxD devices
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: blebox_uniapi
|
|
3
|
-
Version: 2.2.
|
|
3
|
+
Version: 2.2.2
|
|
4
4
|
Summary: Python API for accessing BleBox smart home devices
|
|
5
5
|
Home-page: https://github.com/blebox/blebox_uniapi
|
|
6
6
|
Author: BleBox
|
|
@@ -14,7 +14,6 @@ Classifier: Natural Language :: English
|
|
|
14
14
|
Classifier: Programming Language :: Python :: 3.9
|
|
15
15
|
Classifier: Programming Language :: Python :: 3.10
|
|
16
16
|
Requires-Python: >=3.9
|
|
17
|
-
Description-Content-Type: text/x-rst
|
|
18
17
|
License-File: LICENSE
|
|
19
18
|
Requires-Dist: aiohttp>=3
|
|
20
19
|
|
|
@@ -68,6 +67,11 @@ Credits
|
|
|
68
67
|
=======
|
|
69
68
|
History
|
|
70
69
|
=======
|
|
70
|
+
2.2.2 (2024-02-07)
|
|
71
|
+
------------------
|
|
72
|
+
* fixed wind reading units to get proper raw m/s value (division by 10, see PR #150)
|
|
73
|
+
|
|
74
|
+
|
|
71
75
|
2.2.1 (2024-01-26)
|
|
72
76
|
------------------
|
|
73
77
|
* fixed support for power measurement capabilities of switchBox and switchBoxD devices
|
|
@@ -140,7 +140,13 @@ class Wind(BaseSensor):
|
|
|
140
140
|
def _read_wind_speed(self):
|
|
141
141
|
product = self._product
|
|
142
142
|
if product.last_data is not None:
|
|
143
|
-
|
|
143
|
+
raw = self.raw_value("wind")
|
|
144
|
+
if raw is not None:
|
|
145
|
+
alias = self._alias
|
|
146
|
+
# wind value unit in API is "0.1 m/s" so to get m/s we need to divide by 10
|
|
147
|
+
# min value = 0, max value for sure not bigger than 200km/h so about 60m/s so 600 in API
|
|
148
|
+
return round(product.expect_int(alias, raw, 600, 0) / 10.0, 1)
|
|
149
|
+
return None
|
|
144
150
|
|
|
145
151
|
def after_update(self) -> None:
|
|
146
152
|
self._native_value = self._read_wind_speed()
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: blebox_uniapi
|
|
3
|
-
Version: 2.2.
|
|
3
|
+
Version: 2.2.2
|
|
4
4
|
Summary: Python API for accessing BleBox smart home devices
|
|
5
5
|
Home-page: https://github.com/blebox/blebox_uniapi
|
|
6
6
|
Author: BleBox
|
|
@@ -14,7 +14,6 @@ Classifier: Natural Language :: English
|
|
|
14
14
|
Classifier: Programming Language :: Python :: 3.9
|
|
15
15
|
Classifier: Programming Language :: Python :: 3.10
|
|
16
16
|
Requires-Python: >=3.9
|
|
17
|
-
Description-Content-Type: text/x-rst
|
|
18
17
|
License-File: LICENSE
|
|
19
18
|
Requires-Dist: aiohttp>=3
|
|
20
19
|
|
|
@@ -68,6 +67,11 @@ Credits
|
|
|
68
67
|
=======
|
|
69
68
|
History
|
|
70
69
|
=======
|
|
70
|
+
2.2.2 (2024-02-07)
|
|
71
|
+
------------------
|
|
72
|
+
* fixed wind reading units to get proper raw m/s value (division by 10, see PR #150)
|
|
73
|
+
|
|
74
|
+
|
|
71
75
|
2.2.1 (2024-01-26)
|
|
72
76
|
------------------
|
|
73
77
|
* fixed support for power measurement capabilities of switchBox and switchBoxD devices
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
[bumpversion]
|
|
2
|
-
current_version = 2.2.
|
|
2
|
+
current_version = 2.2.2
|
|
3
3
|
commit = True
|
|
4
4
|
tag = True
|
|
5
5
|
|
|
6
6
|
[bumpversion:file:setup.py]
|
|
7
|
-
search = version=
|
|
8
|
-
replace = version=
|
|
7
|
+
search = version="{current_version}"
|
|
8
|
+
replace = version="{new_version}"
|
|
9
9
|
|
|
10
10
|
[bumpversion:file:blebox_uniapi/__init__.py]
|
|
11
|
-
search = __version__ =
|
|
12
|
-
replace = __version__ =
|
|
11
|
+
search = __version__ = "{current_version}"
|
|
12
|
+
replace = __version__ = "{new_version}"
|
|
13
13
|
|
|
14
14
|
[bdist_wheel]
|
|
15
15
|
universal = 1
|
|
@@ -23,7 +23,7 @@ test_requirements = [
|
|
|
23
23
|
]
|
|
24
24
|
|
|
25
25
|
setup(
|
|
26
|
-
version="2.2.
|
|
26
|
+
version="2.2.2",
|
|
27
27
|
author="BleBox",
|
|
28
28
|
author_email="opensource@blebox.eu",
|
|
29
29
|
python_requires=">=3.9",
|
|
@@ -39,7 +39,6 @@ setup(
|
|
|
39
39
|
install_requires=requirements,
|
|
40
40
|
license="Apache Software License 2.0",
|
|
41
41
|
long_description=readme + "\n\n" + history,
|
|
42
|
-
long_description_content_type="text/x-rst",
|
|
43
42
|
include_package_data=False,
|
|
44
43
|
keywords="blebox_uniapi",
|
|
45
44
|
name="blebox_uniapi",
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Unit test package for blebox_uniapi."""
|
|
@@ -0,0 +1,331 @@
|
|
|
1
|
+
"""PyTest fixtures and test helpers."""
|
|
2
|
+
|
|
3
|
+
import copy
|
|
4
|
+
import json as _json
|
|
5
|
+
import re
|
|
6
|
+
from datetime import date, timedelta
|
|
7
|
+
|
|
8
|
+
import logging
|
|
9
|
+
|
|
10
|
+
from unittest.mock import AsyncMock
|
|
11
|
+
from deepmerge import Merger
|
|
12
|
+
|
|
13
|
+
from unittest import mock
|
|
14
|
+
|
|
15
|
+
from aiohttp import ClientResponseError, ClientSession
|
|
16
|
+
|
|
17
|
+
import pytest
|
|
18
|
+
|
|
19
|
+
from blebox_uniapi.box_types import get_latest_conf
|
|
20
|
+
from blebox_uniapi.session import ApiHost
|
|
21
|
+
from blebox_uniapi.box import Box
|
|
22
|
+
from blebox_uniapi.error import UnsupportedBoxVersion
|
|
23
|
+
|
|
24
|
+
_LOGGER = logging.getLogger(__name__)
|
|
25
|
+
|
|
26
|
+
retype = type(re.compile(""))
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
@pytest.fixture
|
|
30
|
+
def aioclient_mock():
|
|
31
|
+
return AsyncMock(spec=ClientSession)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def array_merge(config, path, base, nxt):
|
|
35
|
+
"""Replace an array element with the merge result of elements."""
|
|
36
|
+
if len(nxt):
|
|
37
|
+
if isinstance(nxt[0], dict):
|
|
38
|
+
index = 0
|
|
39
|
+
for item in nxt:
|
|
40
|
+
if not isinstance(item, dict):
|
|
41
|
+
raise NotImplementedError
|
|
42
|
+
my_merger.merge(base[index], item)
|
|
43
|
+
index += 1
|
|
44
|
+
return base
|
|
45
|
+
elif isinstance(nxt[0], int):
|
|
46
|
+
return [nxt[0]]
|
|
47
|
+
else:
|
|
48
|
+
raise NotImplementedError
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
my_merger = Merger(
|
|
52
|
+
# pass in a list of tuple, with the
|
|
53
|
+
# strategies you are looking to apply
|
|
54
|
+
# to each type.
|
|
55
|
+
[(list, [array_merge]), (dict, ["merge"])],
|
|
56
|
+
# next, choose the fallback strategies,
|
|
57
|
+
# applied to all other types:
|
|
58
|
+
["override"],
|
|
59
|
+
# finally, choose the strategies in
|
|
60
|
+
# the case where the types conflict:
|
|
61
|
+
["override"],
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def jmerge(base, ext):
|
|
66
|
+
"""Create new fixtures by adjusting existing ones."""
|
|
67
|
+
|
|
68
|
+
result = copy.deepcopy(base)
|
|
69
|
+
my_merger.merge(result, _json.loads(ext))
|
|
70
|
+
return result
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def future_date(delta_days=300):
|
|
74
|
+
"""Generate future date string in 'YYYYMMDD' format."""
|
|
75
|
+
future_date = date.today() + timedelta(days=delta_days)
|
|
76
|
+
return future_date.strftime("%Y%m%d")
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
HTTP_MOCKS = {}
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def json_get_expect(mock, url, **kwargs):
|
|
83
|
+
json = kwargs["json"]
|
|
84
|
+
|
|
85
|
+
if mock not in HTTP_MOCKS:
|
|
86
|
+
HTTP_MOCKS[mock] = {}
|
|
87
|
+
HTTP_MOCKS[mock][url] = json
|
|
88
|
+
|
|
89
|
+
class EffectWhenGet:
|
|
90
|
+
def __init__(self, key):
|
|
91
|
+
self._key = key
|
|
92
|
+
|
|
93
|
+
def __call__(self, url, **kwargs):
|
|
94
|
+
data = HTTP_MOCKS[self._key][url]
|
|
95
|
+
response = _json.dumps(data).encode("utf-8")
|
|
96
|
+
status = 200
|
|
97
|
+
return AiohttpClientMockResponse("GET", url, status, response)
|
|
98
|
+
|
|
99
|
+
mock.get = AsyncMock(side_effect=EffectWhenGet(mock))
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def json_post_expect(mock, url, **kwargs):
|
|
103
|
+
json = kwargs["json"]
|
|
104
|
+
params = kwargs["params"]
|
|
105
|
+
|
|
106
|
+
# TODO: check
|
|
107
|
+
# headers = kwargs.get("headers")
|
|
108
|
+
if mock not in HTTP_MOCKS:
|
|
109
|
+
HTTP_MOCKS[mock] = {}
|
|
110
|
+
if url not in HTTP_MOCKS[mock]:
|
|
111
|
+
HTTP_MOCKS[mock][url] = {}
|
|
112
|
+
|
|
113
|
+
HTTP_MOCKS[mock][url][params] = json
|
|
114
|
+
|
|
115
|
+
class EffectWhenPost:
|
|
116
|
+
def __init__(self, key):
|
|
117
|
+
self._key = key
|
|
118
|
+
|
|
119
|
+
def __call__(self, url, **kwargs):
|
|
120
|
+
# TODO: timeout
|
|
121
|
+
params = kwargs.get("data")
|
|
122
|
+
# TODO: better checking of params (content vs raw json)
|
|
123
|
+
data = HTTP_MOCKS[self._key][url][params]
|
|
124
|
+
response = _json.dumps(data).encode("utf-8")
|
|
125
|
+
status = 200
|
|
126
|
+
return AiohttpClientMockResponse("POST", url, status, response)
|
|
127
|
+
|
|
128
|
+
mock.post = AsyncMock(side_effect=EffectWhenPost(mock))
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
class DefaultBoxTest:
|
|
132
|
+
"""Base class with methods common to BleBox integration tests."""
|
|
133
|
+
|
|
134
|
+
IP = "172.0.0.1"
|
|
135
|
+
LOGGER = _LOGGER
|
|
136
|
+
|
|
137
|
+
async def async_entities(self, session):
|
|
138
|
+
"""Get a created entity at the given index."""
|
|
139
|
+
|
|
140
|
+
host = self.IP
|
|
141
|
+
port = 80
|
|
142
|
+
timeout = 2
|
|
143
|
+
api_host = ApiHost(host, port, timeout, session, None, self.LOGGER)
|
|
144
|
+
product = await Box.async_from_host(api_host)
|
|
145
|
+
return [
|
|
146
|
+
self.ENTITY_CLASS(feature) for feature in product.features[self.DEVCLASS]
|
|
147
|
+
]
|
|
148
|
+
|
|
149
|
+
async def allow_get_info(self, aioclient_mock, info=None):
|
|
150
|
+
"""Stub a HTTP GET request for the device state."""
|
|
151
|
+
|
|
152
|
+
data = self.DEVICE_INFO if info is None else info
|
|
153
|
+
|
|
154
|
+
json_get_expect(
|
|
155
|
+
aioclient_mock, f"http://{self.IP}:80/api/device/state", json=data
|
|
156
|
+
)
|
|
157
|
+
if hasattr(self, "DEVICE_EXTENDED_INFO"):
|
|
158
|
+
data = self.DEVICE_EXTENDED_INFO if info is None else info
|
|
159
|
+
json_get_expect(
|
|
160
|
+
aioclient_mock,
|
|
161
|
+
f"http://{self.IP}:80{self.DEVICE_EXTENDED_INFO_PATH}",
|
|
162
|
+
json=data,
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
def allow_get_state(self, aioclient_mock, data):
|
|
166
|
+
"""Stub a HTTP GET request for the product-specific state."""
|
|
167
|
+
json_get_expect(
|
|
168
|
+
aioclient_mock, f"http://{self.IP}:80/{self.DEV_INFO_PATH}", json=data
|
|
169
|
+
)
|
|
170
|
+
|
|
171
|
+
def allow_get(self, aioclient_mock, api_path, data):
|
|
172
|
+
"""Stub a HTTP GET request."""
|
|
173
|
+
json_get_expect(
|
|
174
|
+
aioclient_mock, f"http://{self.IP}:80/{api_path[1:]}", json=data
|
|
175
|
+
)
|
|
176
|
+
|
|
177
|
+
async def allow_post(self, code, aioclient_mock, api_path, post_data, response):
|
|
178
|
+
"""Stub a HTTP POST request."""
|
|
179
|
+
json_post_expect(
|
|
180
|
+
aioclient_mock,
|
|
181
|
+
f"http://{self.IP}:80/{api_path[1:]}",
|
|
182
|
+
params=post_data,
|
|
183
|
+
headers={"content-type": "application/json"},
|
|
184
|
+
json=response,
|
|
185
|
+
)
|
|
186
|
+
await code()
|
|
187
|
+
|
|
188
|
+
# TODO: rename?
|
|
189
|
+
async def updated(self, aioclient_mock, state, index=0):
|
|
190
|
+
"""Return an entry on which update has already been called."""
|
|
191
|
+
|
|
192
|
+
await self.allow_get_info(aioclient_mock)
|
|
193
|
+
entity = (await self.async_entities(aioclient_mock))[index]
|
|
194
|
+
|
|
195
|
+
self.allow_get_state(aioclient_mock, state)
|
|
196
|
+
await entity.async_update()
|
|
197
|
+
return entity
|
|
198
|
+
|
|
199
|
+
async def test_future_version(self, aioclient_mock):
|
|
200
|
+
"""
|
|
201
|
+
Test support for future versions, that is last supported entry in config type file.
|
|
202
|
+
"""
|
|
203
|
+
await self.allow_get_info(aioclient_mock, self.DEVICE_INFO_FUTURE)
|
|
204
|
+
entity = (await self.async_entities(aioclient_mock))[0]
|
|
205
|
+
|
|
206
|
+
assert entity._feature.product._config is get_latest_conf(
|
|
207
|
+
entity._feature.product.type
|
|
208
|
+
)
|
|
209
|
+
|
|
210
|
+
async def test_latest_version(self, aioclient_mock):
|
|
211
|
+
"""
|
|
212
|
+
Test support for latest versions, that is last supported entry in config type file.
|
|
213
|
+
"""
|
|
214
|
+
await self.allow_get_info(aioclient_mock, self.DEVICE_INFO_LATEST)
|
|
215
|
+
entity = (await self.async_entities(aioclient_mock))[0]
|
|
216
|
+
|
|
217
|
+
assert entity._feature.product._config is get_latest_conf(
|
|
218
|
+
entity._feature.product.type
|
|
219
|
+
)
|
|
220
|
+
|
|
221
|
+
async def test_unsupported_version(self, aioclient_mock):
|
|
222
|
+
"""Test version support."""
|
|
223
|
+
|
|
224
|
+
# only gateBox is same
|
|
225
|
+
if self.DEVICE_INFO != self.DEVICE_INFO_UNSUPPORTED:
|
|
226
|
+
await self.allow_get_info(aioclient_mock, self.DEVICE_INFO_UNSUPPORTED)
|
|
227
|
+
with pytest.raises(UnsupportedBoxVersion):
|
|
228
|
+
await self.async_entities(aioclient_mock)
|
|
229
|
+
|
|
230
|
+
async def test_unspecified_version(self, aioclient_mock):
|
|
231
|
+
"""
|
|
232
|
+
Test default_api_level when api level is not specified in device info.
|
|
233
|
+
|
|
234
|
+
"""
|
|
235
|
+
if self.DEVICE_INFO_UNSPECIFIED_API is not None:
|
|
236
|
+
await self.allow_get_info(aioclient_mock, self.DEVICE_INFO_UNSPECIFIED_API)
|
|
237
|
+
with pytest.raises(UnsupportedBoxVersion):
|
|
238
|
+
await self.async_entities(aioclient_mock)
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
class AiohttpClientMockResponse:
|
|
242
|
+
"""Mock Aiohttp client response."""
|
|
243
|
+
|
|
244
|
+
def __init__(
|
|
245
|
+
self, method, url, status, response, cookies=None, exc=None, headers=None
|
|
246
|
+
):
|
|
247
|
+
"""Initialize a fake response."""
|
|
248
|
+
self.method = method
|
|
249
|
+
self._url = url
|
|
250
|
+
self.status = status
|
|
251
|
+
self.response = response
|
|
252
|
+
self.exc = exc
|
|
253
|
+
|
|
254
|
+
self._headers = headers or {}
|
|
255
|
+
self._cookies = {}
|
|
256
|
+
|
|
257
|
+
if cookies:
|
|
258
|
+
for name, data in cookies.items():
|
|
259
|
+
cookie = mock.MagicMock()
|
|
260
|
+
cookie.value = data
|
|
261
|
+
self._cookies[name] = cookie
|
|
262
|
+
|
|
263
|
+
@property
|
|
264
|
+
def headers(self):
|
|
265
|
+
return self._headers
|
|
266
|
+
|
|
267
|
+
@property
|
|
268
|
+
def cookies(self):
|
|
269
|
+
return self._cookies
|
|
270
|
+
|
|
271
|
+
@property
|
|
272
|
+
def url(self):
|
|
273
|
+
return self._url
|
|
274
|
+
|
|
275
|
+
@property
|
|
276
|
+
def content_type(self):
|
|
277
|
+
return self._headers.get("content-type")
|
|
278
|
+
|
|
279
|
+
async def read(self):
|
|
280
|
+
return self.response
|
|
281
|
+
|
|
282
|
+
async def text(self, encoding="utf-8"):
|
|
283
|
+
return self.response.decode(encoding)
|
|
284
|
+
|
|
285
|
+
async def json(self, encoding="utf-8"):
|
|
286
|
+
return _json.loads(self.response.decode(encoding))
|
|
287
|
+
|
|
288
|
+
async def release(self):
|
|
289
|
+
pass
|
|
290
|
+
|
|
291
|
+
def raise_for_status(self):
|
|
292
|
+
"""Raise error if status is 400 or higher."""
|
|
293
|
+
if self.status >= 400:
|
|
294
|
+
request_info = mock.Mock(real_url="http://example.com")
|
|
295
|
+
# TODO: coverage
|
|
296
|
+
raise ClientResponseError(
|
|
297
|
+
request_info=request_info,
|
|
298
|
+
history=None,
|
|
299
|
+
code=self.status,
|
|
300
|
+
headers=self.headers,
|
|
301
|
+
)
|
|
302
|
+
|
|
303
|
+
def close(self):
|
|
304
|
+
pass
|
|
305
|
+
|
|
306
|
+
|
|
307
|
+
class CommonEntity:
|
|
308
|
+
def __init__(self, feature):
|
|
309
|
+
self._feature = feature
|
|
310
|
+
|
|
311
|
+
@property
|
|
312
|
+
def name(self):
|
|
313
|
+
return self._feature.full_name
|
|
314
|
+
|
|
315
|
+
@property
|
|
316
|
+
def unique_id(self):
|
|
317
|
+
return self._feature.unique_id
|
|
318
|
+
|
|
319
|
+
async def async_update(self):
|
|
320
|
+
await self._feature.async_update()
|
|
321
|
+
|
|
322
|
+
@property
|
|
323
|
+
def device_info(self):
|
|
324
|
+
product = self._feature.product
|
|
325
|
+
return {
|
|
326
|
+
"name": product.name,
|
|
327
|
+
"mac": product.unique_id,
|
|
328
|
+
"manufacturer": product.brand,
|
|
329
|
+
"model": product.model,
|
|
330
|
+
"sw_version": product.firmware_version,
|
|
331
|
+
}
|
|
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
|
|
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
|