blueair-api 1.24.1__tar.gz → 1.25.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.
- {blueair_api-1.24.1 → blueair_api-1.25.0}/PKG-INFO +1 -1
- {blueair_api-1.24.1 → blueair_api-1.25.0}/pyproject.toml +1 -1
- {blueair_api-1.24.1 → blueair_api-1.25.0}/src/blueair_api/device_aws.py +2 -0
- {blueair_api-1.24.1 → blueair_api-1.25.0}/src/blueair_api.egg-info/PKG-INFO +1 -1
- {blueair_api-1.24.1 → blueair_api-1.25.0}/src/blueair_api.egg-info/SOURCES.txt +2 -1
- blueair_api-1.25.0/tests/test_device_aws.py +295 -0
- {blueair_api-1.24.1 → blueair_api-1.25.0}/LICENSE +0 -0
- {blueair_api-1.24.1 → blueair_api-1.25.0}/README.md +0 -0
- {blueair_api-1.24.1 → blueair_api-1.25.0}/setup.cfg +0 -0
- {blueair_api-1.24.1 → blueair_api-1.25.0}/src/blueair_api/__init__.py +0 -0
- {blueair_api-1.24.1 → blueair_api-1.25.0}/src/blueair_api/callbacks.py +0 -0
- {blueair_api-1.24.1 → blueair_api-1.25.0}/src/blueair_api/const.py +0 -0
- {blueair_api-1.24.1 → blueair_api-1.25.0}/src/blueair_api/device.py +0 -0
- {blueair_api-1.24.1 → blueair_api-1.25.0}/src/blueair_api/errors.py +0 -0
- {blueair_api-1.24.1 → blueair_api-1.25.0}/src/blueair_api/http_aws_blueair.py +0 -0
- {blueair_api-1.24.1 → blueair_api-1.25.0}/src/blueair_api/http_blueair.py +0 -0
- {blueair_api-1.24.1 → blueair_api-1.25.0}/src/blueair_api/model_enum.py +0 -0
- {blueair_api-1.24.1 → blueair_api-1.25.0}/src/blueair_api/stub.py +0 -0
- {blueair_api-1.24.1 → blueair_api-1.25.0}/src/blueair_api/util.py +0 -0
- {blueair_api-1.24.1 → blueair_api-1.25.0}/src/blueair_api/util_bootstrap.py +0 -0
- {blueair_api-1.24.1 → blueair_api-1.25.0}/src/blueair_api/util_http.py +0 -0
- {blueair_api-1.24.1 → blueair_api-1.25.0}/src/blueair_api.egg-info/dependency_links.txt +0 -0
- {blueair_api-1.24.1 → blueair_api-1.25.0}/src/blueair_api.egg-info/requires.txt +0 -0
- {blueair_api-1.24.1 → blueair_api-1.25.0}/src/blueair_api.egg-info/top_level.txt +0 -0
@@ -1,5 +1,6 @@
|
|
1
1
|
import dataclasses
|
2
2
|
import logging
|
3
|
+
from json import dumps
|
3
4
|
|
4
5
|
from .callbacks import CallbacksMixin
|
5
6
|
from .http_aws_blueair import HttpAwsBlueair
|
@@ -64,6 +65,7 @@ class DeviceAws(CallbacksMixin):
|
|
64
65
|
async def refresh(self):
|
65
66
|
_LOGGER.debug(f"refreshing blueair device aws: {self}")
|
66
67
|
info = await self.api.device_info(self.name_api, self.uuid)
|
68
|
+
_LOGGER.debug(dumps(info, indent=2))
|
67
69
|
sensor_data = convert_api_array_to_dict(info["sensordata"])
|
68
70
|
self.pm1 = safely_get_json_value(sensor_data, "pm1", int)
|
69
71
|
self.pm2_5 = safely_get_json_value(sensor_data, "pm2_5", int)
|
@@ -18,4 +18,5 @@ src/blueair_api.egg-info/PKG-INFO
|
|
18
18
|
src/blueair_api.egg-info/SOURCES.txt
|
19
19
|
src/blueair_api.egg-info/dependency_links.txt
|
20
20
|
src/blueair_api.egg-info/requires.txt
|
21
|
-
src/blueair_api.egg-info/top_level.txt
|
21
|
+
src/blueair_api.egg-info/top_level.txt
|
22
|
+
tests/test_device_aws.py
|
@@ -0,0 +1,295 @@
|
|
1
|
+
"""Tests for DeviceAws.
|
2
|
+
|
3
|
+
Here is one way to run it:
|
4
|
+
|
5
|
+
First install the package in developer mode
|
6
|
+
|
7
|
+
$ pip install -e .
|
8
|
+
|
9
|
+
Then use pytest to drive the tests
|
10
|
+
|
11
|
+
$ pytest tests
|
12
|
+
"""
|
13
|
+
|
14
|
+
from typing import Any
|
15
|
+
|
16
|
+
from importlib import resources
|
17
|
+
from unittest import mock
|
18
|
+
from unittest import IsolatedAsyncioTestCase
|
19
|
+
|
20
|
+
import pytest
|
21
|
+
|
22
|
+
from blueair_api.device_aws import DeviceAws
|
23
|
+
from blueair_api.model_enum import ModelEnum
|
24
|
+
from blueair_api import http_aws_blueair
|
25
|
+
|
26
|
+
class FakeDeviceInfoHelper:
|
27
|
+
"""Fake for the 'device info' interface of HttpAwsBlueAir class."""
|
28
|
+
def __init__(self, info: dict[str, Any]):
|
29
|
+
self.info = info
|
30
|
+
|
31
|
+
async def device_info(self, *args, **kwargs):
|
32
|
+
return self.info
|
33
|
+
|
34
|
+
async def set_device_info(self, device_uuid, service_name, action_verb, action_value):
|
35
|
+
# this function seems to be only updating the states consider rename the method.
|
36
|
+
# action_verb seems to be a type annotation:
|
37
|
+
# c.f. senml: https://www.rfc-editor.org/rfc/rfc8428.html#section-5
|
38
|
+
# the senml parsing library (utils.py) could use some additional love.
|
39
|
+
# to make it more conformal to the RFC standard.
|
40
|
+
for state in self.info['states']:
|
41
|
+
if state['n'] == service_name:
|
42
|
+
break
|
43
|
+
else:
|
44
|
+
state = {'n': service_name}
|
45
|
+
self.info['states'].append(state)
|
46
|
+
# Watch out: mutate after append produces desired mutation to info.
|
47
|
+
state[action_verb] = action_value
|
48
|
+
|
49
|
+
class DeviceAwsTestBase(IsolatedAsyncioTestCase):
|
50
|
+
|
51
|
+
def setUp(self):
|
52
|
+
|
53
|
+
patcher = mock.patch('blueair_api.http_aws_blueair.HttpAwsBlueair', autospec=True)
|
54
|
+
self.api_class = patcher.start()
|
55
|
+
self.addCleanup(patcher.stop)
|
56
|
+
self.api = self.api_class(username="fake-username", password="fake-password")
|
57
|
+
|
58
|
+
self.device = DeviceAws(self.api, name_api="fake-name-api", uuid="fake-uuid", name="fake-name",
|
59
|
+
mac="fake-mac", type_name='fake-type-name')
|
60
|
+
|
61
|
+
self.device_info_helper = FakeDeviceInfoHelper({"sensordata": {}, "states": []})
|
62
|
+
|
63
|
+
self.api.device_info.side_effect = self.device_info_helper.device_info
|
64
|
+
self.api.set_device_info.side_effect = self.device_info_helper.set_device_info
|
65
|
+
|
66
|
+
|
67
|
+
class DeviceAwsSetterTest(DeviceAwsTestBase):
|
68
|
+
"""Tests for all of the setters."""
|
69
|
+
|
70
|
+
async def test_brightness(self):
|
71
|
+
# test cache works
|
72
|
+
self.device.brightness = None
|
73
|
+
await self.device.set_brightness(1)
|
74
|
+
assert self.device.brightness == 1
|
75
|
+
|
76
|
+
# test refresh works
|
77
|
+
await self.device.set_brightness(2)
|
78
|
+
self.device.brightness = None
|
79
|
+
await self.device.refresh()
|
80
|
+
assert self.device.brightness == 2
|
81
|
+
|
82
|
+
async def test_fan_speed(self):
|
83
|
+
# test cache works
|
84
|
+
self.device.fan_speed = None
|
85
|
+
await self.device.set_fan_speed(1)
|
86
|
+
assert self.device.fan_speed == 1
|
87
|
+
|
88
|
+
# test refresh works
|
89
|
+
await self.device.set_fan_speed(2)
|
90
|
+
self.device.fan_speed = None
|
91
|
+
await self.device.refresh()
|
92
|
+
assert self.device.fan_speed == 2
|
93
|
+
|
94
|
+
async def test_running(self):
|
95
|
+
# test cache works
|
96
|
+
self.device.running = None
|
97
|
+
await self.device.set_running(False)
|
98
|
+
assert self.device.running is False
|
99
|
+
|
100
|
+
# test refresh works
|
101
|
+
await self.device.set_running(True)
|
102
|
+
self.device.running = None
|
103
|
+
await self.device.refresh()
|
104
|
+
assert self.device.running is True
|
105
|
+
|
106
|
+
async def test_fan_auto_mode(self):
|
107
|
+
# test cache works
|
108
|
+
self.device.fan_auto_mode = None
|
109
|
+
await self.device.set_fan_auto_mode(False)
|
110
|
+
assert self.device.fan_auto_mode is False
|
111
|
+
|
112
|
+
# test refresh works
|
113
|
+
await self.device.set_fan_auto_mode(True)
|
114
|
+
self.device.fan_auto_mode = None
|
115
|
+
await self.device.refresh()
|
116
|
+
assert self.device.fan_auto_mode is True
|
117
|
+
|
118
|
+
async def test_auto_regulated_humidity(self):
|
119
|
+
# test cache works
|
120
|
+
self.device.auto_regulated_humidity = None
|
121
|
+
await self.device.set_auto_regulated_humidity(1)
|
122
|
+
assert self.device.auto_regulated_humidity == 1
|
123
|
+
|
124
|
+
# test refresh works
|
125
|
+
await self.device.set_auto_regulated_humidity(2)
|
126
|
+
self.device.auto_regulated_humidity = None
|
127
|
+
await self.device.refresh()
|
128
|
+
assert self.device.auto_regulated_humidity == 2
|
129
|
+
|
130
|
+
async def test_child_lock(self):
|
131
|
+
# test cache works
|
132
|
+
self.device.child_lock = None
|
133
|
+
await self.device.set_child_lock(False)
|
134
|
+
assert self.device.child_lock is False
|
135
|
+
|
136
|
+
# test refresh works
|
137
|
+
await self.device.set_child_lock(True)
|
138
|
+
self.device.child_lock = None
|
139
|
+
await self.device.refresh()
|
140
|
+
assert self.device.child_lock is True
|
141
|
+
|
142
|
+
async def test_night_mode(self):
|
143
|
+
# test cache works
|
144
|
+
self.device.night_mode = None
|
145
|
+
await self.device.set_night_mode(False)
|
146
|
+
assert self.device.night_mode is False
|
147
|
+
|
148
|
+
# test refresh works
|
149
|
+
await self.device.set_night_mode(True)
|
150
|
+
self.device.night_mode = None
|
151
|
+
await self.device.refresh()
|
152
|
+
assert self.device.night_mode is True
|
153
|
+
|
154
|
+
async def test_wick_dry_mode(self):
|
155
|
+
# test cache works
|
156
|
+
self.device.wick_dry_mode = None
|
157
|
+
await self.device.set_wick_dry_mode(False)
|
158
|
+
assert self.device.wick_dry_mode is False
|
159
|
+
|
160
|
+
# test refresh works
|
161
|
+
await self.device.set_wick_dry_mode(True)
|
162
|
+
self.device.wick_dry_mode = None
|
163
|
+
await self.device.refresh()
|
164
|
+
assert self.device.wick_dry_mode is True
|
165
|
+
|
166
|
+
|
167
|
+
class UnavailableDeviceAwsTest(DeviceAwsTestBase):
|
168
|
+
"""Tests for a fake device.
|
169
|
+
|
170
|
+
For this fake device, all attrs are unavailable.
|
171
|
+
|
172
|
+
Other device types shall override setUp and populate self.info with the
|
173
|
+
golden dataset.
|
174
|
+
"""
|
175
|
+
|
176
|
+
async def test_attributes(self):
|
177
|
+
|
178
|
+
await self.device.refresh()
|
179
|
+
self.api.device_info.assert_awaited_with("fake-name-api", "fake-uuid")
|
180
|
+
|
181
|
+
device = self.device
|
182
|
+
|
183
|
+
assert device.model == ModelEnum.UNKNOWN
|
184
|
+
|
185
|
+
assert device.pm1 is None
|
186
|
+
assert device.pm2_5 is None
|
187
|
+
assert device.pm10 is None
|
188
|
+
assert device.tVOC is None
|
189
|
+
assert device.temperature is None
|
190
|
+
assert device.humidity is None
|
191
|
+
assert device.name is None
|
192
|
+
assert device.firmware is None
|
193
|
+
assert device.mcu_firmware is None
|
194
|
+
assert device.serial_number is None
|
195
|
+
assert device.sku is None
|
196
|
+
|
197
|
+
assert device.running is False
|
198
|
+
assert device.night_mode is None
|
199
|
+
assert device.germ_shield is None
|
200
|
+
assert device.brightness is None
|
201
|
+
assert device.child_lock is None
|
202
|
+
assert device.fan_speed is None
|
203
|
+
assert device.fan_auto_mode is None
|
204
|
+
assert device.filter_usage is None
|
205
|
+
assert device.wifi_working is None
|
206
|
+
assert device.wick_usage is None
|
207
|
+
assert device.auto_regulated_humidity is None
|
208
|
+
assert device.water_shortage is None
|
209
|
+
|
210
|
+
|
211
|
+
class H35iTest(DeviceAwsTestBase):
|
212
|
+
"""Tests for H35i."""
|
213
|
+
|
214
|
+
def setUp(self):
|
215
|
+
super().setUp()
|
216
|
+
info = eval(resources.files().joinpath('device_info/H35i.txt').read_text())
|
217
|
+
self.device_info_helper.info.update(info)
|
218
|
+
|
219
|
+
async def test_attributes(self):
|
220
|
+
|
221
|
+
await self.device.refresh()
|
222
|
+
self.api.device_info.assert_awaited_with("fake-name-api", "fake-uuid")
|
223
|
+
|
224
|
+
device = self.device
|
225
|
+
|
226
|
+
assert device.model == ModelEnum.HUMIDIFIER_H35I
|
227
|
+
|
228
|
+
assert device.pm1 is None
|
229
|
+
assert device.pm2_5 is None
|
230
|
+
assert device.pm10 is None
|
231
|
+
assert device.tVOC is None
|
232
|
+
assert device.temperature == 19
|
233
|
+
assert device.humidity == 50
|
234
|
+
assert device.name == "Bedroom"
|
235
|
+
assert device.firmware == "1.0.1"
|
236
|
+
assert device.mcu_firmware == "1.0.1"
|
237
|
+
assert device.serial_number == "111163300201110210004036"
|
238
|
+
assert device.sku == "111633"
|
239
|
+
|
240
|
+
assert device.running is True
|
241
|
+
assert device.night_mode is False
|
242
|
+
assert device.germ_shield is None
|
243
|
+
assert device.brightness == 49
|
244
|
+
assert device.child_lock is False
|
245
|
+
assert device.fan_speed == 24
|
246
|
+
assert device.fan_auto_mode is False
|
247
|
+
assert device.filter_usage is None
|
248
|
+
assert device.wifi_working is True
|
249
|
+
assert device.wick_usage == 13
|
250
|
+
assert device.auto_regulated_humidity == 50
|
251
|
+
assert device.water_shortage is False
|
252
|
+
|
253
|
+
|
254
|
+
class T10iTest(DeviceAwsTestBase):
|
255
|
+
"""Tests for T10i."""
|
256
|
+
|
257
|
+
def setUp(self):
|
258
|
+
super().setUp()
|
259
|
+
info = eval(resources.files().joinpath('device_info/T10i.txt').read_text())
|
260
|
+
self.device_info_helper.info.update(info)
|
261
|
+
|
262
|
+
async def test_attributes(self):
|
263
|
+
|
264
|
+
await self.device.refresh()
|
265
|
+
self.api.device_info.assert_awaited_with("fake-name-api", "fake-uuid")
|
266
|
+
|
267
|
+
device = self.device
|
268
|
+
|
269
|
+
assert device.model == ModelEnum.T10I
|
270
|
+
|
271
|
+
assert device.pm1 is None
|
272
|
+
assert device.pm2_5 == 0
|
273
|
+
assert device.pm10 is None
|
274
|
+
assert device.tVOC is None
|
275
|
+
assert device.temperature == 18
|
276
|
+
assert device.humidity == 28
|
277
|
+
assert device.name == "Allen's Office"
|
278
|
+
assert device.firmware == "1.0.4"
|
279
|
+
assert device.mcu_firmware == "1.0.4"
|
280
|
+
assert device.serial_number == "111212400002313210001961"
|
281
|
+
assert device.sku == "112124"
|
282
|
+
|
283
|
+
assert device.running is True
|
284
|
+
assert device.night_mode is None
|
285
|
+
assert device.germ_shield is None
|
286
|
+
assert device.brightness == 100
|
287
|
+
assert device.child_lock is False
|
288
|
+
assert device.fan_speed is None
|
289
|
+
assert device.fan_auto_mode is None
|
290
|
+
assert device.filter_usage == 0
|
291
|
+
assert device.wifi_working is True
|
292
|
+
assert device.wick_usage is None
|
293
|
+
assert device.auto_regulated_humidity is None
|
294
|
+
assert device.water_shortage is None
|
295
|
+
|
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
|