blueair-api 1.9.1__py3-none-any.whl → 1.33.2__py3-none-any.whl

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/__init__.py CHANGED
@@ -4,3 +4,4 @@ from .http_aws_blueair import HttpAwsBlueair
4
4
  from .util_bootstrap import get_devices, get_aws_devices
5
5
  from .device import Device
6
6
  from .device_aws import DeviceAws
7
+ from .model_enum import ModelEnum, FeatureEnum
blueair_api/callbacks.py CHANGED
@@ -4,6 +4,8 @@ _LOGGER = logging.getLogger(__name__)
4
4
 
5
5
 
6
6
  class CallbacksMixin:
7
+ __slots__ = ['_callbacks']
8
+
7
9
  def _setup_callbacks(self):
8
10
  self._callbacks = set()
9
11
 
@@ -20,6 +22,6 @@ class CallbacksMixin:
20
22
  def publish_updates(self) -> None:
21
23
  if not hasattr(self, "_callbacks"):
22
24
  self._setup_callbacks()
23
- _LOGGER.debug(f"{self.name} publishing updates")
25
+ _LOGGER.debug(f"{id(self)} publishing updates")
24
26
  for callback in self._callbacks:
25
27
  callback()
blueair_api/const.py CHANGED
@@ -1,7 +1,5 @@
1
- from typing import Union
2
1
  from collections.abc import Mapping
3
- from typing_extensions import TypedDict
4
-
2
+ from typing import TypedDict
5
3
 
6
4
  SENSITIVE_FIELD_NAMES = [
7
5
  "username",
@@ -11,13 +9,6 @@ SENSITIVE_FIELD_NAMES = [
11
9
  # The BlueAir API uses a fixed API key.
12
10
  API_KEY = "eyJhbGciOiJIUzI1NiJ9.eyJncmFudGVlIjoiYmx1ZWFpciIsImlhdCI6MTQ1MzEyNTYzMiwidmFsaWRpdHkiOi0xLCJqdGkiOiJkNmY3OGE0Yi1iMWNkLTRkZDgtOTA2Yi1kN2JkNzM0MTQ2NzQiLCJwZXJtaXNzaW9ucyI6WyJhbGwiXSwicXVvdGEiOi0xLCJyYXRlTGltaXQiOi0xfQ.CJsfWVzFKKDDA6rWdh-hjVVVE9S3d6Hu9BzXG9htWFw" # noqa: E501
13
11
 
14
- MeasurementBundle = TypedDict(
15
- "MeasurementBundle",
16
- {"sensors": list[str], "datapoints": list[list[Union[int, float]]]},
17
- )
18
-
19
- MeasurementList = list[Mapping[str, Union[int, float]]]
20
-
21
12
  AWS_APIKEYS = {
22
13
  "us": {
23
14
  "gigyaRegion": "us1",
@@ -32,3 +23,11 @@ AWS_APIKEYS = {
32
23
  "apiKey": "3_qRseYzrUJl1VyxvSJANalu_kNgQ83swB1B9uzgms58--5w1ClVNmrFdsDnWVQQCl",
33
24
  },
34
25
  }
26
+
27
+
28
+ class MeasurementBundle(TypedDict):
29
+ sensors: list[str]
30
+ datapoints: list[list[int | float]]
31
+
32
+
33
+ MeasurementList = list[Mapping[str, int | float]]
blueair_api/device.py CHANGED
@@ -1,97 +1,134 @@
1
- import logging
2
-
3
1
  from .callbacks import CallbacksMixin
4
2
  from .http_blueair import HttpBlueair
3
+ from .util import transform_data_points, safely_get_json_value, convert_none_to_not_implemented
4
+ from dataclasses import dataclass, field
5
+ from logging import getLogger
5
6
 
6
- _LOGGER = logging.getLogger(__name__)
7
+ _LOGGER = getLogger(__name__)
7
8
 
8
9
 
10
+ @dataclass(slots=True)
9
11
  class Device(CallbacksMixin):
10
- uuid: str = None
11
- name: str = None
12
- timezone: str = None
13
- compatibility: str = None
14
- model: str = None
15
- mac: str = None
16
- firmware: str = None
17
- mcu_firmware: str = None
18
- wlan_driver: str = None
19
- room_location: str = None
12
+ @classmethod
13
+ async def create_device(cls, api, uuid, name, mac, refresh=False):
14
+ _LOGGER.debug("UUID:"+uuid)
15
+ info = await api.get_info(uuid)
16
+ device = Device(
17
+ api=api,
18
+ uuid=uuid,
19
+ name=name,
20
+ mac=mac,
21
+ timezone=info["timezone"],
22
+ compatibility=info["compatibility"],
23
+ model=info["model"],
24
+ firmware=info["firmware"],
25
+ mcu_firmware=info["mcuFirmware"],
26
+ wlan_driver=info["wlanDriver"],
27
+ room_location=info["roomLocation"]
28
+ )
29
+ if refresh:
30
+ await device.refresh()
31
+ _LOGGER.debug(f"create_device blueair device: {device}")
32
+ return device
33
+
34
+ api: HttpBlueair = field(repr=False)
35
+ raw_info : dict[str: any] = field(repr=False, init=False)
20
36
 
21
- brightness: int = None
22
- child_lock: bool = None
23
- night_mode: bool = None
24
- fan_speed: int = None
25
- fan_mode: str = None
26
- filter_expired: bool = None
27
- wifi_working: bool = None
37
+ uuid: str | None = None
38
+ name: str | None = None
39
+ timezone: str | None = None
40
+ compatibility: str | None = None
41
+ model: str | None = None
42
+ mac: str | None = None
43
+ firmware: str | None = None
44
+ mcu_firmware: str | None = None
45
+ wlan_driver: str | None = None
46
+ room_location: str | None = None
28
47
 
29
- def __init__(
30
- self,
31
- api: HttpBlueair,
32
- uuid: str = None,
33
- name: str = None,
34
- mac: str = None,
35
- ):
36
- self.api = api
37
- self.uuid = uuid
38
- self.name = name
39
- self.mac = mac
40
- _LOGGER.debug(f"creating blueair device: {self.name}")
48
+ brightness: int | None = None
49
+ child_lock: bool | None = None
50
+ night_mode: bool | None = None
51
+ fan_speed: int | None = None
52
+ fan_auto_mode: bool | None = None
53
+ filter_expired: bool | None = None
54
+ wifi_working: bool | None = None
41
55
 
42
- async def init(self):
43
- info = await self.api.get_info(self.uuid)
44
- self.timezone = info["timezone"]
45
- self.compatibility = info["compatibility"]
46
- self.model = info["model"]
47
- self.firmware = info["firmware"]
48
- self.mcu_firmware = info["mcuFirmware"]
49
- self.wlan_driver = info["wlanDriver"]
50
- self.room_location = info["roomLocation"]
56
+ pm1: int | None = NotImplemented
57
+ pm10: int | None = NotImplemented
58
+ pm25: int | None = NotImplemented
59
+ voc: int | None = NotImplemented
60
+ co2: int | None = NotImplemented
61
+ temperature: float | None = NotImplemented
62
+ humidity: float | None = NotImplemented
63
+ all_pollution: float | None = NotImplemented
51
64
 
52
65
  async def refresh(self):
53
66
  _LOGGER.debug("Requesting current attributes...")
67
+ self.raw_info = {}
54
68
  attributes = await self.api.get_attributes(self.uuid)
69
+ self.raw_info["attributes"] = attributes
55
70
  _LOGGER.debug(f"result: {attributes}")
56
71
  if "brightness" in attributes:
57
72
  self.brightness = int(attributes["brightness"])
58
73
  else:
59
- self.brightness = 0
60
- self.child_lock = bool(attributes["child_lock"])
74
+ self.brightness = NotImplemented
75
+ if "child_lock" in attributes:
76
+ self.child_lock = attributes["child_lock"] == "1"
77
+ else:
78
+ self.child_lock = NotImplemented
61
79
  if "night_mode" in attributes:
62
- self.night_mode = bool(attributes["night_mode"])
63
- self.fan_speed = int(attributes["fan_speed"])
64
- self.filter_expired = attributes["filter_status"] != "OK"
65
- self.fan_mode = attributes["mode"]
80
+ self.night_mode = attributes["night_mode"] == "1"
81
+ else:
82
+ self.night_mode = NotImplemented
83
+ if "fan_speed" in attributes:
84
+ self.fan_speed = int(attributes["fan_speed"])
85
+ else:
86
+ self.fan_speed = NotImplemented
87
+ if "filter_status" in attributes:
88
+ self.filter_expired = attributes["filter_status"] != "OK"
89
+ else:
90
+ self.filter_expired = NotImplemented
91
+ if "mode" in attributes:
92
+ self.fan_auto_mode = attributes["mode"] == "auto"
93
+ else:
94
+ self.fan_auto_mode = NotImplemented
66
95
  if "wifi_status" in attributes:
67
96
  self.wifi_working = attributes["wifi_status"] == "1"
68
97
  else:
69
- self.wifi_working = 0
98
+ self.wifi_working = False
99
+ if self.compatibility != "sense+":
100
+ datapoints = transform_data_points(await self.api.get_data_points_since(self.uuid))
101
+ self.raw_info["datapoints"] = datapoints
102
+ for data_point in datapoints:
103
+ _LOGGER.debug(data_point)
104
+ self.pm25 = convert_none_to_not_implemented(safely_get_json_value(data_point, "pm25", int))
105
+ self.pm10 = convert_none_to_not_implemented(safely_get_json_value(data_point, "pm10", int))
106
+ self.pm1 = convert_none_to_not_implemented(safely_get_json_value(data_point, "pm1", int))
107
+ self.voc = convert_none_to_not_implemented(safely_get_json_value(data_point, "voc", int))
108
+ self.co2 = convert_none_to_not_implemented(safely_get_json_value(data_point, "co2", int))
109
+ self.temperature = convert_none_to_not_implemented(safely_get_json_value(data_point, "temperature", int))
110
+ self.humidity = convert_none_to_not_implemented(safely_get_json_value(data_point, "humidity", int))
111
+ self.all_pollution = convert_none_to_not_implemented(safely_get_json_value(data_point, "all_pollution", int))
112
+ _LOGGER.debug(f"refreshed blueair device: {self}")
70
113
  self.publish_updates()
71
114
 
72
- async def set_fan_speed(self, new_speed):
115
+ async def set_fan_speed(self, new_speed: str):
116
+ self.fan_speed = int(new_speed)
73
117
  await self.api.set_fan_speed(self.uuid, new_speed)
118
+ self.publish_updates()
119
+
120
+ async def set_brightness(self, new_brightness: int):
121
+ self.brightness = new_brightness
122
+ await self.api.set_brightness(self.uuid, new_brightness)
123
+ self.publish_updates()
74
124
 
75
- def __repr__(self):
76
- return {
77
- "uuid": self.uuid,
78
- "name": self.name,
79
- "timezone": self.timezone,
80
- "compatibility": self.compatibility,
81
- "model": self.model,
82
- "mac": self.mac,
83
- "firmware": self.firmware,
84
- "mcu_firmware": self.mcu_firmware,
85
- "wlan_driver": self.wlan_driver,
86
- "room_location": self.room_location,
87
- "brightness": self.brightness,
88
- "child_lock": self.child_lock,
89
- "night_mode": self.night_mode,
90
- "fan_speed": self.fan_speed,
91
- "filter_expired": self.filter_expired,
92
- "fan_mode": self.fan_mode,
93
- "wifi_working": self.wifi_working,
94
- }
125
+ async def set_child_lock(self, enabled: bool):
126
+ self.child_lock = enabled
127
+ await self.api.set_child_lock(self.uuid, enabled)
128
+ self.publish_updates()
129
+
130
+ async def set_fan_auto_mode(self, fan_auto_mode: bool):
131
+ self.fan_auto_mode = fan_auto_mode
132
+ await self.api.set_fan_auto_mode(self.uuid, fan_auto_mode)
133
+ self.publish_updates()
95
134
 
96
- def __str__(self):
97
- return f"{self.__repr__()}"
blueair_api/device_aws.py CHANGED
@@ -1,78 +1,150 @@
1
1
  import logging
2
+ from json import dumps
2
3
 
3
4
  from .callbacks import CallbacksMixin
4
5
  from .http_aws_blueair import HttpAwsBlueair
5
- from .util import convert_api_array_to_dict, safely_get_json_value
6
+ from .model_enum import ModelEnum
7
+ from . import intermediate_representation_aws as ir
8
+ from dataclasses import dataclass, field
6
9
 
7
10
  _LOGGER = logging.getLogger(__name__)
8
11
 
12
+ type AttributeType[T] = T | None
9
13
 
14
+ @dataclass(slots=True)
10
15
  class DeviceAws(CallbacksMixin):
11
- uuid: str = None
12
- name: str = None
13
- name_api: str = None
14
- mac: str = None
15
- firmware: str = None
16
- mcu_firmware: str = None
17
- serial_number: str = None
18
-
19
- brightness: int = None
20
- child_lock: int = None
21
- fan_speed: int = None
22
- fan_auto_mode: bool = None
23
- running: bool = None
24
- night_mode: bool = None
25
- germ_shield: bool = None
26
-
27
- pm1: int = None
28
- pm2_5: int = None
29
- pm10: int = None
30
- tVOC: int = None
31
- temperature: int = None
32
- humidity: int = None
33
- filter_usage: int = None # percentage
34
- wifi_working: bool = None
35
-
36
- def __init__(
37
- self,
38
- api: HttpAwsBlueair,
39
- uuid: str = None,
40
- name_api: str = None,
41
- mac: str = None,
42
- ):
43
- self.api = api
44
- self.uuid = uuid
45
- self.name_api = name_api
46
- self.mac = mac
47
- _LOGGER.debug(f"creating blueair device aws: {self.uuid}")
16
+ @classmethod
17
+ async def create_device(cls, api, uuid, name, mac, type_name, refresh=False):
18
+ _LOGGER.debug("UUID:"+uuid)
19
+ device_aws = DeviceAws(
20
+ api=api,
21
+ uuid=uuid,
22
+ name_api=name,
23
+ mac=mac,
24
+ type_name=type_name,
25
+ )
26
+ if refresh:
27
+ await device_aws.refresh()
28
+ _LOGGER.debug(f"create_device blueair device_aws: {device_aws}")
29
+ return device_aws
30
+
31
+ api: HttpAwsBlueair = field(repr=False)
32
+ raw_info : dict[str: any] = field(repr=False, init=False)
33
+
34
+ uuid : str | None = None
35
+ name : str | None = None
36
+ name_api : str | None = None
37
+ mac : str | None = None
38
+ type_name : str | None = None
39
+
40
+ # Attributes are defined below.
41
+ # We mandate that unittests shall test all fields of AttributeType.
42
+ sku : AttributeType[str] = None
43
+ firmware : AttributeType[str] = None
44
+ mcu_firmware : AttributeType[str] = None
45
+ serial_number : AttributeType[str] = None
46
+
47
+ brightness : AttributeType[int] = None
48
+ child_lock : AttributeType[bool] = None
49
+ fan_speed : AttributeType[int] = None
50
+ fan_auto_mode : AttributeType[bool] = None
51
+ standby : AttributeType[bool] = None
52
+ night_mode : AttributeType[bool] = None
53
+ germ_shield : AttributeType[bool] = None
54
+
55
+ pm1 : AttributeType[int] = None
56
+ pm2_5 : AttributeType[int] = None
57
+ pm10 : AttributeType[int] = None
58
+ tVOC : AttributeType[int] = None
59
+ temperature : AttributeType[int] = None
60
+ humidity : AttributeType[int] = None
61
+ filter_usage_percentage : AttributeType[int] = None
62
+ wifi_working : AttributeType[bool] = None
63
+
64
+ wick_usage_percentage : AttributeType[int] = None
65
+ wick_dry_mode : AttributeType[bool] = None
66
+ water_shortage : AttributeType[bool] = None
67
+ auto_regulated_humidity : AttributeType[int] = None
68
+
69
+ main_mode: AttributeType[int] = None # api value 0 purify only, 1 heat on, 2 cool on
70
+ heat_sub_mode: AttributeType[int] = None # api value 1 heat on, 2 heat on with fan auto
71
+ heat_fan_speed: AttributeType[int] = None # api value 11/37/64/91
72
+ heat_temp: AttributeType[int] = None # api value is celsius * 10
73
+ cool_sub_mode: AttributeType[int] = None # api value 1 cool on, 2 cool on with fan auto
74
+ cool_fan_speed: AttributeType[int] = None # api value 11/37/64/91
75
+ ap_sub_mode: AttributeType[int] = None # api value 1 manual speeed, 2 auto fan speed
76
+ fan_speed_0: AttributeType[int] = None # api value 11/37/64/91
77
+ temperature_unit: AttributeType[int] = None # api value of 1 is celcius
48
78
 
49
79
  async def refresh(self):
50
- info = await self.api.device_info(self.name_api, self.uuid)
51
- sensor_data = convert_api_array_to_dict(info["sensordata"])
52
- self.pm1 = safely_get_json_value(sensor_data, "pm1", int)
53
- self.pm2_5 = safely_get_json_value(sensor_data, "pm2_5", int)
54
- self.pm10 = safely_get_json_value(sensor_data, "pm10", int)
55
- self.tVOC = safely_get_json_value(sensor_data, "tVOC", int)
56
- self.temperature = safely_get_json_value(sensor_data, "t", int)
57
- self.humidity = safely_get_json_value(sensor_data, "h", int)
58
-
59
- self.name = safely_get_json_value(info, "configuration.di.name")
60
- self.firmware = safely_get_json_value(info, "configuration.di.cfv")
61
- self.mcu_firmware = safely_get_json_value(info, "configuration.di.mfv")
62
- self.serial_number = safely_get_json_value(info, "configuration.di.ds")
63
-
64
- states = convert_api_array_to_dict(info["states"])
65
- self.running = safely_get_json_value(states, "standby") is False
66
- self.night_mode = safely_get_json_value(states, "nightmode", bool)
67
- self.germ_shield = safely_get_json_value(states, "germshield", bool)
68
- self.brightness = safely_get_json_value(states, "brightness", int)
69
- self.child_lock = safely_get_json_value(states, "childlock")
70
- self.fan_speed = safely_get_json_value(states, "fanspeed", int)
71
- self.fan_auto_mode = safely_get_json_value(states, "automode", bool)
72
- self.filter_usage = safely_get_json_value(states, "filterusage", int)
73
- self.wifi_working = safely_get_json_value(states, "online", bool)
80
+ _LOGGER.debug(f"refreshing blueair device aws: {self}")
81
+ self.raw_info = await self.api.device_info(self.name_api, self.uuid)
82
+ _LOGGER.debug(dumps(self.raw_info, indent=2))
83
+
84
+ # ir.parse_json(ir.Attribute, ir.query_json(info, "configuration.da"))
85
+ ds = ir.parse_json(ir.Sensor, ir.query_json(self.raw_info, "configuration.ds"))
86
+ dc = ir.parse_json(ir.Control, ir.query_json(self.raw_info, "configuration.dc"))
87
+
88
+ sensor_data = ir.SensorPack(self.raw_info["sensordata"]).to_latest_value()
89
+
90
+ def sensor_data_safe_get(key):
91
+ return sensor_data.get(key) if key in ds else NotImplemented
92
+
93
+ self.pm1 = sensor_data_safe_get("pm1")
94
+ self.pm2_5 = sensor_data_safe_get("pm2_5")
95
+ self.pm10 = sensor_data_safe_get("pm10")
96
+ self.tVOC = sensor_data_safe_get("tVOC")
97
+ self.temperature = sensor_data_safe_get("t")
98
+ self.humidity = sensor_data_safe_get("h")
99
+
100
+ def info_safe_get(path):
101
+ # directly reads for the schema. If the schema field is
102
+ # undefined, it is NotImplemented, not merely unavailable.
103
+ value = ir.query_json(self.raw_info, path)
104
+ if value is None:
105
+ return NotImplemented
106
+ return value
107
+
108
+ self.name = info_safe_get("configuration.di.name")
109
+ self.firmware = info_safe_get("configuration.di.cfv")
110
+ self.mcu_firmware = info_safe_get("configuration.di.mfv")
111
+ self.serial_number = info_safe_get("configuration.di.ds")
112
+ self.sku = info_safe_get("configuration.di.sku")
113
+
114
+ states = ir.SensorPack(self.raw_info["states"]).to_latest_value()
115
+
116
+ def states_safe_get(key):
117
+ return states.get(key) if key in dc else NotImplemented
118
+
119
+ # "online" is not defined in the schema.
120
+ self.wifi_working = states.get("online")
121
+
122
+ self.standby = states_safe_get("standby")
123
+ self.night_mode = states_safe_get("nightmode")
124
+ self.germ_shield = states_safe_get("germshield")
125
+ self.brightness = states_safe_get("brightness")
126
+ self.child_lock = states_safe_get("childlock")
127
+ self.fan_speed = states_safe_get("fanspeed")
128
+ self.fan_auto_mode = states_safe_get("automode")
129
+ self.filter_usage_percentage = states_safe_get("filterusage")
130
+
131
+ self.wick_usage_percentage = states_safe_get("wickusage")
132
+ self.wick_dry_mode = states_safe_get("wickdrys")
133
+ self.auto_regulated_humidity = states_safe_get("autorh")
134
+ self.water_shortage = states_safe_get("wshortage")
135
+
136
+ self.main_mode = states_safe_get("mainmode")
137
+ self.heat_temp = states_safe_get("heattemp")
138
+ self.heat_sub_mode = states_safe_get("heatsubmode")
139
+ self.heat_fan_speed = states_safe_get("heatfs")
140
+ self.cool_sub_mode = states_safe_get("coolsubmode")
141
+ self.cool_fan_speed = states_safe_get("coolfs")
142
+ self.ap_sub_mode = states_safe_get("apsubmode")
143
+ self.fan_speed_0 = states_safe_get("fsp0")
144
+ self.temperature_unit = states_safe_get("tu")
74
145
 
75
146
  self.publish_updates()
147
+ _LOGGER.debug(f"refreshed blueair device aws: {self}")
76
148
 
77
149
  async def set_brightness(self, value: int):
78
150
  self.brightness = value
@@ -84,9 +156,9 @@ class DeviceAws(CallbacksMixin):
84
156
  await self.api.set_device_info(self.uuid, "fanspeed", "v", value)
85
157
  self.publish_updates()
86
158
 
87
- async def set_running(self, running: bool):
88
- self.running = running
89
- await self.api.set_device_info(self.uuid, "standby", "vb", not running)
159
+ async def set_standby(self, value: bool):
160
+ self.standby = value
161
+ await self.api.set_device_info(self.uuid, "standby", "vb", value)
90
162
  self.publish_updates()
91
163
 
92
164
  async def set_fan_auto_mode(self, fan_auto_mode: bool):
@@ -94,6 +166,11 @@ class DeviceAws(CallbacksMixin):
94
166
  await self.api.set_device_info(self.uuid, "automode", "vb", fan_auto_mode)
95
167
  self.publish_updates()
96
168
 
169
+ async def set_auto_regulated_humidity(self, value: int):
170
+ self.auto_regulated_humidity = value
171
+ await self.api.set_device_info(self.uuid, "autorh", "v", value)
172
+ self.publish_updates()
173
+
97
174
  async def set_child_lock(self, child_lock: bool):
98
175
  self.child_lock = child_lock
99
176
  await self.api.set_device_info(self.uuid, "childlock", "vb", child_lock)
@@ -104,30 +181,70 @@ class DeviceAws(CallbacksMixin):
104
181
  await self.api.set_device_info(self.uuid, "nightmode", "vb", night_mode)
105
182
  self.publish_updates()
106
183
 
107
- def __repr__(self):
108
- return {
109
- "uuid": self.uuid,
110
- "name": self.name,
111
- "name_api": self.name_api,
112
- "mac": self.mac,
113
- "firmware": self.firmware,
114
- "mcu_firmware": self.mcu_firmware,
115
- "serial_number": self.serial_number,
116
- "brightness": self.brightness,
117
- "child_lock": self.child_lock,
118
- "fan_speed": self.fan_speed,
119
- "fan_auto_mode": self.fan_auto_mode,
120
- "running": self.running,
121
- "night_mode": self.night_mode,
122
- "germ_shield": self.germ_shield,
123
- "pm1": self.pm1,
124
- "pm2_5": self.pm2_5,
125
- "pm10": self.pm10,
126
- "tVOC": self.tVOC,
127
- "temperature": self.temperature,
128
- "humidity": self.humidity,
129
- "filter_usage": self.filter_usage,
130
- }
131
-
132
- def __str__(self):
133
- return f"{self.__repr__()}"
184
+ async def set_wick_dry_mode(self, value: bool):
185
+ self.wick_dry_mode = value
186
+ await self.api.set_device_info(self.uuid, "wickdrys", "vb", value)
187
+ self.publish_updates()
188
+
189
+ async def set_germ_shield(self, value: bool):
190
+ self.germ_shield = value
191
+ await self.api.set_device_info(self.uuid, "germshield", "vb", value)
192
+ self.publish_updates()
193
+
194
+ async def set_main_mode(self, value: int):
195
+ self.main_mode = value
196
+ await self.api.set_device_info(self.uuid, "mainmode", "v", value)
197
+ self.publish_updates()
198
+
199
+ async def set_heat_temp(self, value: int):
200
+ self.heat_temp = value
201
+ await self.api.set_device_info(self.uuid, "heattemp", "v", value)
202
+ self.publish_updates()
203
+
204
+ async def set_heat_sub_mode(self, value: int):
205
+ self.heat_sub_mode = value
206
+ await self.api.set_device_info(self.uuid, "heatsubmode", "v", value)
207
+ self.publish_updates()
208
+
209
+ async def set_heat_fan_speed(self, value: int):
210
+ self.heat_fan_speed = value
211
+ await self.api.set_device_info(self.uuid, "heatfs", "v", value)
212
+ self.publish_updates()
213
+
214
+ async def set_cool_sub_mode(self, value: int):
215
+ self.cool_sub_mode = value
216
+ await self.api.set_device_info(self.uuid, "coolsubmode", "v", value)
217
+ self.publish_updates()
218
+
219
+ async def set_cool_fan_speed(self, value: int):
220
+ self.cool_fan_speed = value
221
+ await self.api.set_device_info(self.uuid, "coolfs", "v", value)
222
+ self.publish_updates()
223
+
224
+ async def set_ap_sub_mode(self, value: int):
225
+ self.ap_sub_mode = value
226
+ await self.api.set_device_info(self.uuid, "apsubmode", "v", value)
227
+ self.publish_updates()
228
+
229
+ async def set_fan_speed_0(self, value: int):
230
+ self.fan_speed_0 = value
231
+ await self.api.set_device_info(self.uuid, "fsp0", "v", value)
232
+ self.publish_updates()
233
+
234
+ @property
235
+ def model(self) -> ModelEnum:
236
+ if self.sku == "111633":
237
+ return ModelEnum.HUMIDIFIER_H35I
238
+ if self.sku == "105820":
239
+ return ModelEnum.PROTECT_7440I
240
+ if self.sku == "105826":
241
+ return ModelEnum.PROTECT_7470I
242
+ if self.sku == "110059":
243
+ return ModelEnum.MAX_211I
244
+ if self.sku == "110092":
245
+ return ModelEnum.MAX_311I
246
+ if self.sku == "110057":
247
+ return ModelEnum.MAX_411I
248
+ if self.sku == "112124":
249
+ return ModelEnum.T10I
250
+ return ModelEnum.UNKNOWN