Skip to content

Commit 335c8e5

Browse files
authored
Add switchbot_cloud climate TURN_OFF, TURN_ON support. (home-assistant#154017)
1 parent 8152a9e commit 335c8e5

File tree

2 files changed

+134
-1
lines changed

2 files changed

+134
-1
lines changed

homeassistant/components/switchbot_cloud/climate.py

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,10 @@ class SwitchBotCloudAirConditioner(SwitchBotCloudEntity, ClimateEntity, RestoreE
6666

6767
_attr_assumed_state = True
6868
_attr_supported_features = (
69-
ClimateEntityFeature.FAN_MODE | ClimateEntityFeature.TARGET_TEMPERATURE
69+
ClimateEntityFeature.FAN_MODE
70+
| ClimateEntityFeature.TARGET_TEMPERATURE
71+
| ClimateEntityFeature.TURN_OFF
72+
| ClimateEntityFeature.TURN_ON
7073
)
7174
_attr_fan_modes = [
7275
FanState.FAN_AUTO,
@@ -161,3 +164,17 @@ async def async_set_temperature(self, **kwargs: Any) -> None:
161164
await self._do_send_command(temperature=temperature)
162165
self._attr_target_temperature = temperature
163166
self.async_write_ha_state()
167+
168+
async def async_turn_off(self) -> None:
169+
"""Turn climate entity off."""
170+
await self.async_set_hvac_mode(HVACMode.OFF)
171+
172+
async def async_turn_on(self) -> None:
173+
"""Turn climate entity on.
174+
175+
Uses the last known hvac_mode (if not OFF), otherwise defaults to FAN_ONLY.
176+
"""
177+
hvac_mode = self._attr_hvac_mode
178+
if hvac_mode == HVACMode.OFF:
179+
hvac_mode = HVACMode.FAN_ONLY
180+
await self.async_set_hvac_mode(hvac_mode)

tests/components/switchbot_cloud/test_climate.py

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
SERVICE_SET_FAN_MODE,
1313
SERVICE_SET_HVAC_MODE,
1414
SERVICE_SET_TEMPERATURE,
15+
SERVICE_TURN_OFF,
16+
SERVICE_TURN_ON,
1517
)
1618
from homeassistant.components.switchbot_cloud import SwitchBotAPI
1719
from homeassistant.config_entries import ConfigEntryState
@@ -180,3 +182,117 @@ async def test_air_conditioner_no_last_state(
180182
assert state.state == "fan_only"
181183
assert state.attributes[ATTR_FAN_MODE] == "auto"
182184
assert state.attributes[ATTR_TEMPERATURE] == 21
185+
186+
187+
async def test_air_conditioner_turn_off(
188+
hass: HomeAssistant, mock_list_devices, mock_get_status
189+
) -> None:
190+
"""Test the climate.turn_off service."""
191+
mock_list_devices.return_value = [
192+
Remote(
193+
deviceId="ac-device-id-1",
194+
deviceName="climate-1",
195+
remoteType="DIY Air Conditioner",
196+
hubDeviceId="test-hub-id",
197+
),
198+
]
199+
200+
entry = await configure_integration(hass)
201+
assert entry.state is ConfigEntryState.LOADED
202+
203+
entity_id = "climate.climate_1"
204+
assert hass.states.get(entity_id).state == "fan_only"
205+
206+
with patch.object(SwitchBotAPI, "send_command") as mock_send_command:
207+
await hass.services.async_call(
208+
CLIMATE_DOMAIN,
209+
SERVICE_TURN_OFF,
210+
{ATTR_ENTITY_ID: entity_id},
211+
blocking=True,
212+
)
213+
mock_send_command.assert_called_once()
214+
assert "21,4,1,off" in str(mock_send_command.call_args)
215+
216+
assert hass.states.get(entity_id).state == "off"
217+
218+
219+
async def test_air_conditioner_turn_on(
220+
hass: HomeAssistant, mock_list_devices, mock_get_status
221+
) -> None:
222+
"""Test turning on a climate entity that has a non-off HVAC_STATE."""
223+
mock_list_devices.return_value = [
224+
Remote(
225+
deviceId="ac-device-id-1",
226+
deviceName="climate-1",
227+
remoteType="DIY Air Conditioner",
228+
hubDeviceId="test-hub-id",
229+
),
230+
]
231+
232+
mock_state = State(
233+
"climate.climate_1",
234+
"cool",
235+
{
236+
ATTR_FAN_MODE: "high",
237+
ATTR_TEMPERATURE: 25,
238+
},
239+
)
240+
mock_restore_cache(hass, (mock_state,))
241+
entry = await configure_integration(hass)
242+
assert entry.state is ConfigEntryState.LOADED
243+
244+
entity_id = "climate.climate_1"
245+
assert hass.states.get(entity_id).state == "cool"
246+
247+
with patch.object(SwitchBotAPI, "send_command") as mock_turn_on_command:
248+
await hass.services.async_call(
249+
CLIMATE_DOMAIN,
250+
SERVICE_TURN_ON,
251+
{ATTR_ENTITY_ID: entity_id},
252+
blocking=True,
253+
)
254+
mock_turn_on_command.assert_called_once()
255+
assert "25,2,4,on" in str(mock_turn_on_command.call_args)
256+
257+
assert hass.states.get(entity_id).state == "cool"
258+
259+
260+
async def test_air_conditioner_turn_on_from_hvac_mode_off(
261+
hass: HomeAssistant, mock_list_devices, mock_get_status
262+
) -> None:
263+
"""Test turning on a climate entity that has an off HVAC_STATE."""
264+
mock_list_devices.return_value = [
265+
Remote(
266+
deviceId="ac-device-id-1",
267+
deviceName="climate-1",
268+
remoteType="DIY Air Conditioner",
269+
hubDeviceId="test-hub-id",
270+
),
271+
]
272+
273+
mock_state = State(
274+
"climate.climate_1",
275+
"off",
276+
{
277+
ATTR_FAN_MODE: "high",
278+
ATTR_TEMPERATURE: 25,
279+
},
280+
)
281+
mock_restore_cache(hass, (mock_state,))
282+
entry = await configure_integration(hass)
283+
assert entry.state is ConfigEntryState.LOADED
284+
285+
entity_id = "climate.climate_1"
286+
assert hass.states.get(entity_id).state == "off"
287+
288+
with patch.object(SwitchBotAPI, "send_command") as mock_turn_on_command:
289+
await hass.services.async_call(
290+
CLIMATE_DOMAIN,
291+
SERVICE_TURN_ON,
292+
{ATTR_ENTITY_ID: entity_id},
293+
blocking=True,
294+
)
295+
mock_turn_on_command.assert_called_once()
296+
assert "25,4,4,on" in str(mock_turn_on_command.call_args)
297+
298+
assert hass.states.get(entity_id).state == "fan_only"

0 commit comments

Comments
 (0)