pyvesync 3.0.0__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.
Files changed (50) hide show
  1. pyvesync/__init__.py +5 -0
  2. pyvesync/base_devices/__init__.py +35 -0
  3. pyvesync/base_devices/bulb_base.py +330 -0
  4. pyvesync/base_devices/fan_base.py +392 -0
  5. pyvesync/base_devices/fryer_base.py +68 -0
  6. pyvesync/base_devices/humidifier_base.py +462 -0
  7. pyvesync/base_devices/outlet_base.py +327 -0
  8. pyvesync/base_devices/purifier_base.py +525 -0
  9. pyvesync/base_devices/switch_base.py +271 -0
  10. pyvesync/base_devices/thermostat_base.py +283 -0
  11. pyvesync/base_devices/vesyncbasedevice.py +572 -0
  12. pyvesync/const.py +825 -0
  13. pyvesync/device_container.py +373 -0
  14. pyvesync/device_map.py +1172 -0
  15. pyvesync/devices/__init__.py +1 -0
  16. pyvesync/devices/vesyncbulb.py +1126 -0
  17. pyvesync/devices/vesyncfan.py +233 -0
  18. pyvesync/devices/vesynchumidifier.py +808 -0
  19. pyvesync/devices/vesynckitchen.py +651 -0
  20. pyvesync/devices/vesyncoutlet.py +954 -0
  21. pyvesync/devices/vesyncpurifier.py +990 -0
  22. pyvesync/devices/vesyncswitch.py +415 -0
  23. pyvesync/devices/vesyncthermostat.py +171 -0
  24. pyvesync/models/__init__.py +11 -0
  25. pyvesync/models/base_models.py +129 -0
  26. pyvesync/models/bulb_models.py +197 -0
  27. pyvesync/models/bypass_models.py +289 -0
  28. pyvesync/models/fan_models.py +47 -0
  29. pyvesync/models/fryer_models.py +34 -0
  30. pyvesync/models/home_models.py +169 -0
  31. pyvesync/models/humidifier_models.py +202 -0
  32. pyvesync/models/outlet_models.py +220 -0
  33. pyvesync/models/purifier_models.py +261 -0
  34. pyvesync/models/switch_models.py +101 -0
  35. pyvesync/models/thermostat_models.py +134 -0
  36. pyvesync/models/vesync_models.py +439 -0
  37. pyvesync/utils/__init__.py +1 -0
  38. pyvesync/utils/colors.py +250 -0
  39. pyvesync/utils/device_mixins.py +362 -0
  40. pyvesync/utils/enum_utils.py +26 -0
  41. pyvesync/utils/errors.py +867 -0
  42. pyvesync/utils/helpers.py +700 -0
  43. pyvesync/utils/logs.py +525 -0
  44. pyvesync/vesync.py +638 -0
  45. pyvesync/vesynchome.py +152 -0
  46. pyvesync-3.0.0.dist-info/METADATA +567 -0
  47. pyvesync-3.0.0.dist-info/RECORD +50 -0
  48. pyvesync-3.0.0.dist-info/WHEEL +5 -0
  49. pyvesync-3.0.0.dist-info/licenses/LICENSE +21 -0
  50. pyvesync-3.0.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,271 @@
1
+ """Base classes for all VeSync switches."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import logging
6
+ from typing import TYPE_CHECKING
7
+
8
+ from typing_extensions import deprecated
9
+
10
+ from pyvesync.base_devices.vesyncbasedevice import DeviceState, VeSyncBaseToggleDevice
11
+ from pyvesync.const import SwitchFeatures
12
+ from pyvesync.utils.colors import Color
13
+
14
+ if TYPE_CHECKING:
15
+ from pyvesync import VeSync
16
+ from pyvesync.device_map import SwitchMap
17
+ from pyvesync.models.vesync_models import ResponseDeviceDetailsModel
18
+ from pyvesync.utils.colors import HSV, RGB
19
+
20
+ logger = logging.getLogger(__name__)
21
+
22
+
23
+ class SwitchState(DeviceState):
24
+ """VeSync Switch State Base.
25
+
26
+ Args:
27
+ device (VeSyncSwitch): The switch device.
28
+ details (ResponseDeviceDetailsModel): The switch device details.
29
+ feature_map (SwitchMap): The switch feature map.
30
+
31
+ Attributes:
32
+ _exclude_serialization (list[str]): List of attributes to exclude from
33
+ serialization.
34
+ active_time (int): Active time of device, defaults to None.
35
+ connection_status (str): Connection status of device.
36
+ device (VeSyncBaseDevice): Device object.
37
+ device_status (str): Device status.
38
+ features (dict): Features of device.
39
+ last_update_ts (int): Last update timestamp of device, defaults to None.
40
+ backlight_color (Color): The backlight color of the switch.
41
+ brightness (int): The brightness level of the switch.
42
+ backlight_status (str): The status of the backlight.
43
+ indicator_status (str): The status of the indicator light.
44
+ """
45
+
46
+ __slots__ = (
47
+ '_backlight_color',
48
+ 'backlight_status',
49
+ 'brightness',
50
+ 'indicator_status',
51
+ )
52
+
53
+ def __init__(
54
+ self,
55
+ device: VeSyncSwitch,
56
+ details: ResponseDeviceDetailsModel,
57
+ feature_map: SwitchMap,
58
+ ) -> None:
59
+ """Initialize VeSync Switch State."""
60
+ super().__init__(device, details, feature_map)
61
+ self.device: VeSyncSwitch = device
62
+ self._backlight_color: Color | None = None
63
+ self.brightness: int | None = None
64
+ self.active_time: int | None = 0
65
+ self.backlight_status: str | None = None
66
+ self.indicator_status: str | None = None
67
+
68
+ @property
69
+ def backlight_rgb(self) -> RGB | None:
70
+ """Get backlight RGB color."""
71
+ if not self.device.supports_backlight_color:
72
+ logger.warning('Backlight color not supported.')
73
+ if isinstance(self._backlight_color, Color):
74
+ return self._backlight_color.rgb
75
+ return None
76
+
77
+ @property
78
+ def backlight_hsv(self) -> HSV | None:
79
+ """Get backlight HSV color."""
80
+ if not self.device.supports_backlight_color:
81
+ logger.warning('Backlight color not supported.')
82
+ if isinstance(self._backlight_color, Color):
83
+ return self._backlight_color.hsv
84
+ return None
85
+
86
+ @property
87
+ def backlight_color(self) -> Color | None:
88
+ """Get backlight color."""
89
+ if isinstance(self._backlight_color, Color):
90
+ return self._backlight_color
91
+ logger.warning('Backlight color not supported.')
92
+ return None
93
+
94
+ @backlight_color.setter
95
+ def backlight_color(self, color: Color | None) -> None:
96
+ """Set backlight color."""
97
+ if not self.device.supports_backlight_color:
98
+ logger.warning('Backlight color not supported.')
99
+ return
100
+ self._backlight_color = color
101
+
102
+
103
+ class VeSyncSwitch(VeSyncBaseToggleDevice):
104
+ """Etekcity Switch Base Class.
105
+
106
+ Abstract Base Class for Etekcity Switch Devices, inheriting from
107
+ pyvesync.base_devices.vesyncbasedevice.VeSyncBaseDevice. Should not be
108
+ instantiated directly, subclassed by VeSyncWallSwitch and VeSyncDimmerSwitch.
109
+
110
+ Attributes:
111
+ state (SwitchState): Switch state object.
112
+ last_response (ResponseInfo): Last response from API call.
113
+ manager (VeSync): Manager object for API calls.
114
+ device_name (str): Name of device.
115
+ device_image (str): URL for device image.
116
+ cid (str): Device ID.
117
+ connection_type (str): Connection type of device.
118
+ device_type (str): Type of device.
119
+ type (str): Type of device.
120
+ uuid (str): UUID of device, not always present.
121
+ config_module (str): Configuration module of device.
122
+ mac_id (str): MAC ID of device.
123
+ current_firm_version (str): Current firmware version of device.
124
+ device_region (str): Region of device. (US, EU, etc.)
125
+ pid (str): Product ID of device, pulled by some devices on update.
126
+ sub_device_no (int): Sub-device number of device.
127
+ product_type (str): Product type of device.
128
+ features (dict): Features of device.
129
+ """
130
+
131
+ __slots__ = ()
132
+
133
+ def __init__(
134
+ self, details: ResponseDeviceDetailsModel, manager: VeSync, feature_map: SwitchMap
135
+ ) -> None:
136
+ """Initialize Switch Base Class."""
137
+ super().__init__(details, manager, feature_map)
138
+ self.state: SwitchState = SwitchState(self, details, feature_map)
139
+
140
+ @property
141
+ @deprecated('Use `supports_dimmable` property instead.')
142
+ def is_dimmable(self) -> bool:
143
+ """Return True if switch is dimmable."""
144
+ return bool(SwitchFeatures.DIMMABLE in self.features)
145
+
146
+ @property
147
+ def supports_backlight_color(self) -> bool:
148
+ """Return True if switch supports backlight."""
149
+ return bool(SwitchFeatures.BACKLIGHT_RGB in self.features)
150
+
151
+ @property
152
+ def supports_indicator_light(self) -> bool:
153
+ """Return True if switch supports indicator."""
154
+ return bool(SwitchFeatures.INDICATOR_LIGHT in self.features)
155
+
156
+ @property
157
+ def supports_backlight(self) -> bool:
158
+ """Return True if switch supports backlight."""
159
+ return bool(SwitchFeatures.BACKLIGHT in self.features)
160
+
161
+ @property
162
+ def supports_dimmable(self) -> bool:
163
+ """Return True if switch is dimmable."""
164
+ return bool(SwitchFeatures.DIMMABLE in self.features)
165
+
166
+ async def toggle_indicator_light(self, toggle: bool | None = None) -> bool:
167
+ """Toggle indicator light on or off.
168
+
169
+ Args:
170
+ toggle (bool): True to turn on, False to turn off. If None, toggles the state
171
+
172
+ Returns:
173
+ bool: True if successful, False otherwise.
174
+ """
175
+ del toggle
176
+ if self.supports_indicator_light:
177
+ logger.debug('toggle_indicator_light not configured for %s', self.device_name)
178
+ else:
179
+ logger.debug('toggle_indicator_light not supported for %s', self.device_name)
180
+ return False
181
+
182
+ async def turn_on_indicator_light(self) -> bool:
183
+ """Turn on indicator light if supported."""
184
+ return await self.toggle_indicator_light(True)
185
+
186
+ async def turn_off_indicator_light(self) -> bool:
187
+ """Turn off indicator light if supported."""
188
+ return await self.toggle_indicator_light(False)
189
+
190
+ async def set_backlight_status(
191
+ self,
192
+ status: bool,
193
+ red: int | None = None,
194
+ green: int | None = None,
195
+ blue: int | None = None,
196
+ ) -> bool:
197
+ """Set the backlight status and optionally its color if supported by the device.
198
+
199
+ Args:
200
+ status (bool): Backlight status (True for ON, False for OFF).
201
+ red (int | None): RGB green value (0-255), defaults to None.
202
+ green (int | None): RGB green value (0-255), defaults to None.
203
+ blue (int | None): RGB blue value (0-255), defaults to None.
204
+
205
+ Returns:
206
+ bool: True if successful, False otherwise.
207
+
208
+ """
209
+ del status, red, green, blue
210
+ if self.supports_backlight:
211
+ logger.debug('set_backlight_status not configured for %s', self.device_name)
212
+ else:
213
+ logger.debug('set_backlight_status not supported for %s', self.device_name)
214
+ return False
215
+
216
+ async def turn_on_rgb_backlight(self) -> bool:
217
+ """Turn on backlight if supported."""
218
+ return await self.set_backlight_status(True)
219
+
220
+ async def turn_off_rgb_backlight(self) -> bool:
221
+ """Turn off backlight if supported."""
222
+ return await self.set_backlight_status(False)
223
+
224
+ @deprecated('Use `turn_on_rgb_backlight()` instead.')
225
+ async def turn_rgb_backlight_on(self) -> bool:
226
+ """Turn on RGB backlight if supported."""
227
+ return await self.set_backlight_status(True)
228
+
229
+ @deprecated('Use `turn_off_rgb_backlight()` instead.')
230
+ async def turn_rgb_backlight_off(self) -> bool:
231
+ """Turn off RGB backlight if supported."""
232
+ return await self.set_backlight_status(False)
233
+
234
+ async def set_backlight_color(self, red: int, green: int, blue: int) -> bool:
235
+ """Set the color of the backlight using RGB.
236
+
237
+ Args:
238
+ red (int): Red value (0-255).
239
+ green (int): Green value (0-255).
240
+ blue (int): Blue value (0-255).
241
+
242
+ Returns:
243
+ bool: True if successful, False otherwise.
244
+ """
245
+ return await self.set_backlight_status(True, red=red, green=green, blue=blue)
246
+
247
+ async def set_brightness(self, brightness: int) -> bool:
248
+ """Set the brightness of the switch if supported.
249
+
250
+ Args:
251
+ brightness (int): Brightness value (0-100).
252
+
253
+ Returns:
254
+ bool: True if successful, False otherwise.
255
+ """
256
+ del brightness
257
+ if self.supports_dimmable:
258
+ logger.debug('set_brightness not configured for %s', self.device_name)
259
+ else:
260
+ logger.debug('set_brightness not supported for %s', self.device_name)
261
+ return False
262
+
263
+ @deprecated('Use `turn_on_indicator_light` instead.')
264
+ async def turn_indicator_light_on(self) -> bool:
265
+ """Deprecated - use turn_on_indicator_light."""
266
+ return await self.toggle_indicator_light(True)
267
+
268
+ @deprecated('Use `turn_off_indicator_light` instead.')
269
+ async def turn_indicator_light_off(self) -> bool:
270
+ """Deprecated - use turn_off_indicator_light."""
271
+ return await self.toggle_indicator_light(False)
@@ -0,0 +1,283 @@
1
+ """Base classes for thermostat devices."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import logging
6
+ from typing import TYPE_CHECKING
7
+
8
+ from pyvesync.base_devices.vesyncbasedevice import DeviceState, VeSyncBaseDevice
9
+ from pyvesync.const import (
10
+ ThermostatConst,
11
+ ThermostatEcoTypes,
12
+ ThermostatFanModes,
13
+ ThermostatFanStatus,
14
+ ThermostatHoldOptions,
15
+ ThermostatScheduleOrHoldOptions,
16
+ ThermostatWorkModes,
17
+ ThermostatWorkStatusCodes,
18
+ )
19
+
20
+ if TYPE_CHECKING:
21
+ from pyvesync import VeSync
22
+ from pyvesync.device_map import ThermostatMap
23
+ from pyvesync.models.thermostat_models import (
24
+ ThermostatMinorDetails,
25
+ ThermostatSimpleRoutine,
26
+ )
27
+ from pyvesync.models.vesync_models import ResponseDeviceDetailsModel
28
+
29
+
30
+ _LOGGER = logging.getLogger(__name__)
31
+
32
+
33
+ class ThermostatState(DeviceState):
34
+ """VeSync Thermostat State.
35
+
36
+ Args:
37
+ device (VeSyncThermostat): The thermostat device.
38
+ details (ResponseDeviceDetailsModel): The thermostat device details.
39
+ feature_map (ThermostatMap): The thermostat feature map.
40
+ """
41
+
42
+ __slots__ = (
43
+ 'alert_status',
44
+ 'battery_level',
45
+ 'configuration',
46
+ 'cool_to_temp',
47
+ 'deadband',
48
+ 'device_config',
49
+ 'eco_type',
50
+ 'fan_mode',
51
+ 'fan_status',
52
+ 'filter_life',
53
+ 'heat_to_temp',
54
+ 'hold_end_time',
55
+ 'hold_option',
56
+ 'humidity',
57
+ 'lock_status',
58
+ 'mode',
59
+ 'routine_running_id',
60
+ 'routines',
61
+ 'schedule_or_hold',
62
+ 'temperature',
63
+ 'temperature_unit',
64
+ 'work_mode',
65
+ 'work_status',
66
+ )
67
+
68
+ def __init__(
69
+ self,
70
+ device: VeSyncThermostat,
71
+ details: ResponseDeviceDetailsModel,
72
+ feature_map: ThermostatMap,
73
+ ) -> None:
74
+ """Initialize VeSync Thermostat State."""
75
+ super().__init__(device, details, feature_map)
76
+ self.device: VeSyncThermostat = device
77
+ self.configuration: ThermostatMinorDetails | None = None
78
+ self.work_mode: ThermostatWorkModes | None = None
79
+ self.work_status: ThermostatWorkStatusCodes | None = None
80
+ self.fan_mode: ThermostatFanModes | None = None
81
+ self.fan_status: ThermostatFanStatus | None = None
82
+ self.temperature_unit: str | None = None
83
+ self.temperature: float | None = None
84
+ self.humidity: int | None = None
85
+ self.heat_to_temp: int | None = None
86
+ self.cool_to_temp: int | None = None
87
+ self.lock_status: bool = False
88
+ self.schedule_or_hold: ThermostatScheduleOrHoldOptions | None = None
89
+ self.hold_end_time: int | None = None
90
+ self.hold_option: ThermostatHoldOptions | None = None
91
+ self.deadband: int | None = None
92
+ self.eco_type: ThermostatEcoTypes | None = None
93
+ self.alert_status: int | None = None
94
+ self.routines: list[ThermostatSimpleRoutine] = []
95
+ self.routine_running_id: int | None = None
96
+ self.battery_level: int | None = None
97
+ self.filter_life: int | None = None
98
+
99
+ @property
100
+ def is_running(self) -> bool:
101
+ """Check if the thermostat is running."""
102
+ return self.work_status != ThermostatWorkStatusCodes.OFF
103
+
104
+ @property
105
+ def is_heating(self) -> bool:
106
+ """Check if the thermostat is heating."""
107
+ return self.work_status == ThermostatWorkStatusCodes.HEATING
108
+
109
+ @property
110
+ def is_cooling(self) -> bool:
111
+ """Check if the thermostat is cooling."""
112
+ return self.work_status == ThermostatWorkStatusCodes.COOLING
113
+
114
+ @property
115
+ def is_fan_on(self) -> bool:
116
+ """Check if the fan is on."""
117
+ return self.fan_status == ThermostatFanStatus.ON
118
+
119
+
120
+ class VeSyncThermostat(VeSyncBaseDevice):
121
+ """Base class for VeSync Thermostat devices.
122
+
123
+ Args:
124
+ details (ResponseDeviceDetailsModel): The thermostat device details.
125
+ manager (VeSync): The VeSync manager instance.
126
+ feature_map (ThermostatMap): The thermostat feature map.
127
+ """
128
+
129
+ __slots__ = ('eco_types', 'fan_modes', 'hold_options', 'supported_work_modes')
130
+
131
+ def __init__(
132
+ self,
133
+ details: ResponseDeviceDetailsModel,
134
+ manager: VeSync,
135
+ feature_map: ThermostatMap,
136
+ ) -> None:
137
+ """Initialize VeSync Thermostat."""
138
+ super().__init__(details, manager, feature_map)
139
+ self.state: ThermostatState = ThermostatState(self, details, feature_map)
140
+ self.fan_modes = feature_map.fan_modes
141
+ self.supported_work_modes = feature_map.modes
142
+ self.eco_types = feature_map.eco_types
143
+ self.hold_options = feature_map.hold_options
144
+
145
+ async def set_mode(self, mode: ThermostatWorkModes) -> bool:
146
+ """Set the thermostat mode."""
147
+ del mode # Unused
148
+ _LOGGER.debug('set mode not implemented for %s', self.device_type)
149
+ return False
150
+
151
+ async def turn_off(self) -> bool:
152
+ """Set mode to off."""
153
+ return await self.set_mode(ThermostatWorkModes.OFF)
154
+
155
+ async def set_mode_cool(self) -> bool:
156
+ """Set mode to cool."""
157
+ return await self.set_mode(ThermostatWorkModes.COOL)
158
+
159
+ async def set_mode_heat(self) -> bool:
160
+ """Set mode to heat."""
161
+ return await self.set_mode(ThermostatWorkModes.HEAT)
162
+
163
+ async def set_mode_auto(self) -> bool:
164
+ """Set mode to auto."""
165
+ return await self.set_mode(ThermostatWorkModes.AUTO)
166
+
167
+ async def set_mode_smart_auto(self) -> bool:
168
+ """Set mode to smart auto."""
169
+ return await self.set_mode(ThermostatWorkModes.SMART_AUTO)
170
+
171
+ async def set_mode_emergency_heat(self) -> bool:
172
+ """Set mode to emergency heat."""
173
+ return await self.set_mode(ThermostatWorkModes.EM_HEAT)
174
+
175
+ async def set_fan_mode(self, mode: ThermostatFanModes) -> bool:
176
+ """Set thermostat fan mode."""
177
+ del mode
178
+ _LOGGER.debug('set fan mode not implemented for %s', self.device_type)
179
+ return False
180
+
181
+ async def set_fan_ciruclate(self) -> bool:
182
+ """Set fan circulate."""
183
+ return await self.set_fan_mode(ThermostatConst.FanMode.CIRCULATE)
184
+
185
+ async def set_fan_auto(self) -> bool:
186
+ """Set fan auto."""
187
+ return await self.set_fan_mode(ThermostatConst.FanMode.AUTO)
188
+
189
+ async def set_fan_on(self) -> bool:
190
+ """Set fan on."""
191
+ return await self.set_fan_mode(ThermostatConst.FanMode.ON)
192
+
193
+ async def get_configuration(self) -> None:
194
+ """Retrieve configuration from API."""
195
+ _LOGGER.debug('get configuration not implemented for %s', self.device_type)
196
+
197
+ async def set_temp_point(self, temperature: float) -> bool:
198
+ """Set the temperature point."""
199
+ del temperature
200
+ _LOGGER.debug('set temp point not implemented for %s', self.device_type)
201
+ return False
202
+
203
+ async def cancel_hold(self) -> bool:
204
+ """Cancel the scheduled hold."""
205
+ _LOGGER.debug('cancel hold not implemented for %s', self.device_type)
206
+ return False
207
+
208
+ async def set_cool_to_temp(self, temperature: float) -> bool:
209
+ """Set the cool to temperature.
210
+
211
+ Args:
212
+ temperature (float): The cool to temperature.
213
+
214
+ Returns:
215
+ bool: True if successful, False otherwise.
216
+ """
217
+ del temperature
218
+ _LOGGER.debug('set cool to temp not implemented for %s', self.device_type)
219
+ return False
220
+
221
+ async def set_heat_to_temp(self, temperature: float) -> bool:
222
+ """Set the heat to temperature.
223
+
224
+ Args:
225
+ temperature (float): The heat to temperature.
226
+
227
+ Returns:
228
+ bool: True if successful, False otherwise.
229
+ """
230
+ del temperature
231
+ _LOGGER.debug('set heat to temp not implemented for %s', self.device_type)
232
+ return False
233
+
234
+ async def toggle_lock(self, toggle: bool, pin: int | str | None = None) -> bool:
235
+ """Toggle the thermostat lock status."""
236
+ del toggle, pin
237
+ _LOGGER.debug('toggle lock not implemented for %s', self.device_type)
238
+ return False
239
+
240
+ async def turn_on_lock(self, pin: int | str) -> bool:
241
+ """Turn on the thermostat lock.
242
+
243
+ Args:
244
+ pin (int | str): The 4-digit PIN code.
245
+ """
246
+ return await self.toggle_lock(True, pin)
247
+
248
+ async def turn_off_lock(self) -> bool:
249
+ """Turn off the thermostat lock."""
250
+ return await self.toggle_lock(False)
251
+
252
+ async def set_eco_type(self, eco_type: ThermostatEcoTypes) -> bool:
253
+ """Set thermostat eco type.
254
+
255
+ Args:
256
+ eco_type (ThermostatEcoTypes): The eco type to set, options are found in
257
+ self.eco_types.
258
+
259
+ Returns:
260
+ bool: True if successful, False otherwise.
261
+ """
262
+ del eco_type
263
+ if not self.eco_types:
264
+ _LOGGER.debug('No eco types available for %s', self.device_type)
265
+ else:
266
+ _LOGGER.debug('set_eco_type not configured for %s', self.device_name)
267
+ return False
268
+
269
+ async def set_eco_first(self) -> bool:
270
+ """Set eco first."""
271
+ return await self.set_eco_type(ThermostatEcoTypes.ECO_FIRST)
272
+
273
+ async def set_eco_second(self) -> bool:
274
+ """Set eco second."""
275
+ return await self.set_eco_type(ThermostatEcoTypes.ECO_SECOND)
276
+
277
+ async def set_eco_comfort_first(self) -> bool:
278
+ """Set eco comfort."""
279
+ return await self.set_eco_type(ThermostatEcoTypes.COMFORT_FIRST)
280
+
281
+ async def set_eco_comfort_second(self) -> bool:
282
+ """Set eco comfort."""
283
+ return await self.set_eco_type(ThermostatEcoTypes.COMFORT_SECOND)