|
1 | 1 | """Support for SwitchBot Air Conditioner remotes.""" |
2 | 2 |
|
| 3 | +import asyncio |
3 | 4 | from logging import getLogger |
4 | 5 | from typing import Any |
5 | 6 |
|
6 | | -from switchbot_api import AirConditionerCommands |
| 7 | +from switchbot_api import ( |
| 8 | + AirConditionerCommands, |
| 9 | + Device, |
| 10 | + Remote, |
| 11 | + SmartRadiatorThermostatCommands, |
| 12 | + SmartRadiatorThermostatMode, |
| 13 | + SwitchBotAPI, |
| 14 | +) |
7 | 15 |
|
8 | 16 | from homeassistant.components import climate as FanState |
9 | 17 | from homeassistant.components.climate import ( |
10 | 18 | ATTR_FAN_MODE, |
11 | 19 | ATTR_TEMPERATURE, |
| 20 | + PRESET_AWAY, |
| 21 | + PRESET_BOOST, |
| 22 | + PRESET_COMFORT, |
| 23 | + PRESET_ECO, |
| 24 | + PRESET_HOME, |
| 25 | + PRESET_NONE, |
| 26 | + PRESET_SLEEP, |
12 | 27 | ClimateEntity, |
13 | 28 | ClimateEntityFeature, |
14 | 29 | HVACMode, |
15 | 30 | ) |
16 | 31 | from homeassistant.config_entries import ConfigEntry |
17 | | -from homeassistant.const import STATE_UNAVAILABLE, STATE_UNKNOWN, UnitOfTemperature |
18 | | -from homeassistant.core import HomeAssistant |
| 32 | +from homeassistant.const import ( |
| 33 | + PRECISION_TENTHS, |
| 34 | + STATE_UNAVAILABLE, |
| 35 | + STATE_UNKNOWN, |
| 36 | + UnitOfTemperature, |
| 37 | +) |
| 38 | +from homeassistant.core import HomeAssistant, callback |
19 | 39 | from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback |
20 | 40 | from homeassistant.helpers.restore_state import RestoreEntity |
21 | 41 |
|
22 | | -from . import SwitchbotCloudData |
23 | | -from .const import DOMAIN |
| 42 | +from . import SwitchbotCloudData, SwitchBotCoordinator |
| 43 | +from .const import DOMAIN, SMART_RADIATOR_THERMOSTAT_AFTER_COMMAND_REFRESH |
24 | 44 | from .entity import SwitchBotCloudEntity |
25 | 45 |
|
26 | 46 | _LOGGER = getLogger(__name__) |
@@ -53,7 +73,7 @@ async def async_setup_entry( |
53 | 73 | """Set up SwitchBot Cloud entry.""" |
54 | 74 | data: SwitchbotCloudData = hass.data[DOMAIN][config.entry_id] |
55 | 75 | async_add_entities( |
56 | | - SwitchBotCloudAirConditioner(data.api, device, coordinator) |
| 76 | + _async_make_entity(data.api, device, coordinator) |
57 | 77 | for device, coordinator in data.devices.climates |
58 | 78 | ) |
59 | 79 |
|
@@ -178,3 +198,122 @@ async def async_turn_on(self) -> None: |
178 | 198 | if hvac_mode == HVACMode.OFF: |
179 | 199 | hvac_mode = HVACMode.FAN_ONLY |
180 | 200 | await self.async_set_hvac_mode(hvac_mode) |
| 201 | + |
| 202 | + |
| 203 | +RADIATOR_PRESET_MODE_MAP: dict[str, SmartRadiatorThermostatMode] = { |
| 204 | + PRESET_NONE: SmartRadiatorThermostatMode.OFF, |
| 205 | + PRESET_ECO: SmartRadiatorThermostatMode.ENERGY_SAVING, |
| 206 | + PRESET_BOOST: SmartRadiatorThermostatMode.FAST_HEATING, |
| 207 | + PRESET_COMFORT: SmartRadiatorThermostatMode.COMFORT, |
| 208 | + PRESET_HOME: SmartRadiatorThermostatMode.MANUAL, |
| 209 | +} |
| 210 | + |
| 211 | +RADIATOR_HA_PRESET_MODE_MAP = { |
| 212 | + value: key for key, value in RADIATOR_PRESET_MODE_MAP.items() |
| 213 | +} |
| 214 | + |
| 215 | + |
| 216 | +class SwitchBotCloudSmartRadiatorThermostat(SwitchBotCloudEntity, ClimateEntity): |
| 217 | + """Representation of a Smart Radiator Thermostat.""" |
| 218 | + |
| 219 | + _attr_name = None |
| 220 | + |
| 221 | + _attr_supported_features = ( |
| 222 | + ClimateEntityFeature.TARGET_TEMPERATURE | ClimateEntityFeature.PRESET_MODE |
| 223 | + ) |
| 224 | + |
| 225 | + _attr_max_temp = 35 |
| 226 | + _attr_min_temp = 4 |
| 227 | + _attr_target_temperature_step = PRECISION_TENTHS |
| 228 | + _attr_temperature_unit = UnitOfTemperature.CELSIUS |
| 229 | + |
| 230 | + _attr_preset_modes = [ |
| 231 | + PRESET_NONE, |
| 232 | + PRESET_ECO, |
| 233 | + PRESET_AWAY, |
| 234 | + PRESET_BOOST, |
| 235 | + PRESET_COMFORT, |
| 236 | + PRESET_HOME, |
| 237 | + PRESET_SLEEP, |
| 238 | + ] |
| 239 | + _attr_preset_mode = PRESET_HOME |
| 240 | + |
| 241 | + _attr_hvac_modes = [ |
| 242 | + HVACMode.OFF, |
| 243 | + HVACMode.HEAT, |
| 244 | + ] |
| 245 | + |
| 246 | + async def async_set_temperature(self, **kwargs: Any) -> None: |
| 247 | + """Set target temperature.""" |
| 248 | + self._attr_target_temperature = kwargs["temperature"] |
| 249 | + await self.send_api_command( |
| 250 | + command=SmartRadiatorThermostatCommands.SET_MANUAL_MODE_TEMPERATURE, |
| 251 | + parameters=str(self._attr_target_temperature), |
| 252 | + ) |
| 253 | + |
| 254 | + await asyncio.sleep(SMART_RADIATOR_THERMOSTAT_AFTER_COMMAND_REFRESH) |
| 255 | + await self.coordinator.async_request_refresh() |
| 256 | + |
| 257 | + async def async_set_preset_mode(self, preset_mode: str) -> None: |
| 258 | + """Set preset mode.""" |
| 259 | + await self.send_api_command( |
| 260 | + command=SmartRadiatorThermostatCommands.SET_MODE, |
| 261 | + parameters=RADIATOR_PRESET_MODE_MAP[preset_mode].value, |
| 262 | + ) |
| 263 | + self._attr_preset_mode = preset_mode |
| 264 | + |
| 265 | + if self.preset_mode == PRESET_HOME: |
| 266 | + self._attr_target_temperature = self.current_temperature |
| 267 | + else: |
| 268 | + self._attr_target_temperature = None |
| 269 | + |
| 270 | + await asyncio.sleep(SMART_RADIATOR_THERMOSTAT_AFTER_COMMAND_REFRESH) |
| 271 | + await self.coordinator.async_request_refresh() |
| 272 | + |
| 273 | + async def async_set_hvac_mode(self, hvac_mode: HVACMode) -> None: |
| 274 | + """Set target hvac mode.""" |
| 275 | + if hvac_mode is HVACMode.OFF: |
| 276 | + await self.send_api_command( |
| 277 | + command=SmartRadiatorThermostatCommands.SET_MODE, |
| 278 | + parameters=RADIATOR_PRESET_MODE_MAP[PRESET_NONE].value, |
| 279 | + ) |
| 280 | + self._attr_preset_mode = PRESET_NONE |
| 281 | + else: |
| 282 | + await self.send_api_command( |
| 283 | + command=SmartRadiatorThermostatCommands.SET_MODE, |
| 284 | + parameters=RADIATOR_PRESET_MODE_MAP[PRESET_BOOST].value, |
| 285 | + ) |
| 286 | + self._attr_preset_mode = PRESET_BOOST |
| 287 | + self._attr_target_temperature = None |
| 288 | + self._attr_hvac_mode = hvac_mode |
| 289 | + await asyncio.sleep(SMART_RADIATOR_THERMOSTAT_AFTER_COMMAND_REFRESH) |
| 290 | + await self.coordinator.async_request_refresh() |
| 291 | + |
| 292 | + def _set_attributes(self) -> None: |
| 293 | + """Set attributes from coordinator data.""" |
| 294 | + if self.coordinator.data is None: |
| 295 | + return |
| 296 | + mode: int = self.coordinator.data["mode"] |
| 297 | + temperature: str = self.coordinator.data["temperature"] |
| 298 | + self._attr_current_temperature = float(temperature) |
| 299 | + self._attr_preset_mode = RADIATOR_HA_PRESET_MODE_MAP[ |
| 300 | + SmartRadiatorThermostatMode(mode) |
| 301 | + ] |
| 302 | + |
| 303 | + if self.preset_mode in [PRESET_NONE, PRESET_AWAY]: |
| 304 | + self._attr_hvac_mode = HVACMode.OFF |
| 305 | + else: |
| 306 | + self._attr_hvac_mode = HVACMode.HEAT |
| 307 | + if self.preset_mode == PRESET_HOME: |
| 308 | + self._attr_target_temperature = self._attr_current_temperature |
| 309 | + self.async_write_ha_state() |
| 310 | + |
| 311 | + |
| 312 | +@callback |
| 313 | +def _async_make_entity( |
| 314 | + api: SwitchBotAPI, device: Device | Remote, coordinator: SwitchBotCoordinator |
| 315 | +) -> SwitchBotCloudAirConditioner | SwitchBotCloudSmartRadiatorThermostat: |
| 316 | + """Make a climate entity.""" |
| 317 | + if device.device_type == "Smart Radiator Thermostat": |
| 318 | + return SwitchBotCloudSmartRadiatorThermostat(api, device, coordinator) |
| 319 | + return SwitchBotCloudAirConditioner(api, device, coordinator) |
0 commit comments