From 98adeb607008a17ecff81d31b143c47fb8fecfeb Mon Sep 17 00:00:00 2001 From: Jan Bouwhuis <jbouwh@users.noreply.github.com> Date: Mon, 7 Mar 2022 15:38:33 +0100 Subject: [PATCH] Fix false positive MQTT climate deprecation warnings for defaults (#67661) Co-authored-by: Martin Hjelmare <marhje52@gmail.com> --- homeassistant/components/mqtt/climate.py | 32 +++++-- tests/components/mqtt/test_climate.py | 113 +++++++++++++++++++++++ 2 files changed, 136 insertions(+), 9 deletions(-) diff --git a/homeassistant/components/mqtt/climate.py b/homeassistant/components/mqtt/climate.py index e145edde7d7..94320cc5def 100644 --- a/homeassistant/components/mqtt/climate.py +++ b/homeassistant/components/mqtt/climate.py @@ -271,7 +271,7 @@ _PLATFORM_SCHEMA_BASE = SCHEMA_BASE.extend( vol.Optional(CONF_HOLD_COMMAND_TOPIC): mqtt.valid_publish_topic, vol.Optional(CONF_HOLD_STATE_TEMPLATE): cv.template, vol.Optional(CONF_HOLD_STATE_TOPIC): mqtt.valid_subscribe_topic, - vol.Optional(CONF_HOLD_LIST, default=list): cv.ensure_list, + vol.Optional(CONF_HOLD_LIST): cv.ensure_list, vol.Optional(CONF_MODE_COMMAND_TEMPLATE): cv.template, vol.Optional(CONF_MODE_COMMAND_TOPIC): mqtt.valid_publish_topic, vol.Optional( @@ -298,7 +298,7 @@ _PLATFORM_SCHEMA_BASE = SCHEMA_BASE.extend( ), vol.Optional(CONF_RETAIN, default=mqtt.DEFAULT_RETAIN): cv.boolean, # CONF_SEND_IF_OFF is deprecated, support will be removed with release 2022.9 - vol.Optional(CONF_SEND_IF_OFF, default=True): cv.boolean, + vol.Optional(CONF_SEND_IF_OFF): cv.boolean, vol.Optional(CONF_ACTION_TEMPLATE): cv.template, vol.Optional(CONF_ACTION_TOPIC): mqtt.valid_subscribe_topic, # CONF_PRESET_MODE_COMMAND_TOPIC and CONF_PRESET_MODES_LIST must be used together @@ -431,6 +431,12 @@ class MqttClimate(MqttEntity, ClimateEntity): self._feature_preset_mode = False self._optimistic_preset_mode = None + # CONF_SEND_IF_OFF is deprecated, support will be removed with release 2022.9 + self._send_if_off = True + # AWAY and HOLD mode topics and templates are deprecated, + # support will be removed with release 2022.9 + self._hold_list = [] + MqttEntity.__init__(self, hass, config, config_entry, discovery_data) @staticmethod @@ -499,6 +505,15 @@ class MqttClimate(MqttEntity, ClimateEntity): self._command_templates = command_templates + # CONF_SEND_IF_OFF is deprecated, support will be removed with release 2022.9 + if CONF_SEND_IF_OFF in config: + self._send_if_off = config[CONF_SEND_IF_OFF] + + # AWAY and HOLD mode topics and templates are deprecated, + # support will be removed with release 2022.9 + if CONF_HOLD_LIST in config: + self._hold_list = config[CONF_HOLD_LIST] + def _prepare_subscribe_topics(self): # noqa: C901 """(Re)Subscribe to topics.""" topics = {} @@ -806,7 +821,9 @@ class MqttClimate(MqttEntity, ClimateEntity): ): presets.append(PRESET_AWAY) - presets.extend(self._config[CONF_HOLD_LIST]) + # AWAY and HOLD mode topics and templates are deprecated, + # support will be removed with release 2022.9 + presets.extend(self._hold_list) if presets: presets.insert(0, PRESET_NONE) @@ -847,10 +864,7 @@ class MqttClimate(MqttEntity, ClimateEntity): setattr(self, attr, temp) # CONF_SEND_IF_OFF is deprecated, support will be removed with release 2022.9 - if ( - self._config[CONF_SEND_IF_OFF] - or self._current_operation != HVAC_MODE_OFF - ): + if self._send_if_off or self._current_operation != HVAC_MODE_OFF: payload = self._command_templates[cmnd_template](temp) await self._publish(cmnd_topic, payload) @@ -890,7 +904,7 @@ class MqttClimate(MqttEntity, ClimateEntity): async def async_set_swing_mode(self, swing_mode): """Set new swing mode.""" # CONF_SEND_IF_OFF is deprecated, support will be removed with release 2022.9 - if self._config[CONF_SEND_IF_OFF] or self._current_operation != HVAC_MODE_OFF: + if self._send_if_off or self._current_operation != HVAC_MODE_OFF: payload = self._command_templates[CONF_SWING_MODE_COMMAND_TEMPLATE]( swing_mode ) @@ -903,7 +917,7 @@ class MqttClimate(MqttEntity, ClimateEntity): async def async_set_fan_mode(self, fan_mode): """Set new target temperature.""" # CONF_SEND_IF_OFF is deprecated, support will be removed with release 2022.9 - if self._config[CONF_SEND_IF_OFF] or self._current_operation != HVAC_MODE_OFF: + if self._send_if_off or self._current_operation != HVAC_MODE_OFF: payload = self._command_templates[CONF_FAN_MODE_COMMAND_TEMPLATE](fan_mode) await self._publish(CONF_FAN_MODE_COMMAND_TOPIC, payload) diff --git a/tests/components/mqtt/test_climate.py b/tests/components/mqtt/test_climate.py index c3501267e12..93249e76875 100644 --- a/tests/components/mqtt/test_climate.py +++ b/tests/components/mqtt/test_climate.py @@ -333,6 +333,43 @@ async def test_set_fan_mode(hass, mqtt_mock): assert state.attributes.get("fan_mode") == "high" +# CONF_SEND_IF_OFF is deprecated, support will be removed with release 2022.9 +@pytest.mark.parametrize( + "send_if_off,assert_async_publish", + [ + ({}, [call("fan-mode-topic", "low", 0, False)]), + ({"send_if_off": True}, [call("fan-mode-topic", "low", 0, False)]), + ({"send_if_off": False}, []), + ], +) +async def test_set_fan_mode_send_if_off( + hass, mqtt_mock, send_if_off, assert_async_publish +): + """Test setting of fan mode if the hvac is off.""" + config = copy.deepcopy(DEFAULT_CONFIG) + config[CLIMATE_DOMAIN].update(send_if_off) + assert await async_setup_component(hass, CLIMATE_DOMAIN, config) + await hass.async_block_till_done() + assert hass.states.get(ENTITY_CLIMATE) is not None + + # Turn on HVAC + await common.async_set_hvac_mode(hass, "cool", ENTITY_CLIMATE) + mqtt_mock.async_publish.reset_mock() + # Updates for fan_mode should be sent when the device is turned on + await common.async_set_fan_mode(hass, "high", ENTITY_CLIMATE) + mqtt_mock.async_publish.assert_called_once_with("fan-mode-topic", "high", 0, False) + + # Turn off HVAC + await common.async_set_hvac_mode(hass, "off", ENTITY_CLIMATE) + state = hass.states.get(ENTITY_CLIMATE) + assert state.state == "off" + + # Updates for fan_mode should be sent if SEND_IF_OFF is not set or is True + mqtt_mock.async_publish.reset_mock() + await common.async_set_fan_mode(hass, "low", ENTITY_CLIMATE) + mqtt_mock.async_publish.assert_has_calls(assert_async_publish) + + async def test_set_swing_mode_bad_attr(hass, mqtt_mock, caplog): """Test setting swing mode without required attribute.""" assert await async_setup_component(hass, CLIMATE_DOMAIN, DEFAULT_CONFIG) @@ -385,6 +422,43 @@ async def test_set_swing(hass, mqtt_mock): assert state.attributes.get("swing_mode") == "on" +# CONF_SEND_IF_OFF is deprecated, support will be removed with release 2022.9 +@pytest.mark.parametrize( + "send_if_off,assert_async_publish", + [ + ({}, [call("swing-mode-topic", "on", 0, False)]), + ({"send_if_off": True}, [call("swing-mode-topic", "on", 0, False)]), + ({"send_if_off": False}, []), + ], +) +async def test_set_swing_mode_send_if_off( + hass, mqtt_mock, send_if_off, assert_async_publish +): + """Test setting of swing mode if the hvac is off.""" + config = copy.deepcopy(DEFAULT_CONFIG) + config[CLIMATE_DOMAIN].update(send_if_off) + assert await async_setup_component(hass, CLIMATE_DOMAIN, config) + await hass.async_block_till_done() + assert hass.states.get(ENTITY_CLIMATE) is not None + + # Turn on HVAC + await common.async_set_hvac_mode(hass, "cool", ENTITY_CLIMATE) + mqtt_mock.async_publish.reset_mock() + # Updates for swing_mode should be sent when the device is turned on + await common.async_set_swing_mode(hass, "off", ENTITY_CLIMATE) + mqtt_mock.async_publish.assert_called_once_with("swing-mode-topic", "off", 0, False) + + # Turn off HVAC + await common.async_set_hvac_mode(hass, "off", ENTITY_CLIMATE) + state = hass.states.get(ENTITY_CLIMATE) + assert state.state == "off" + + # Updates for swing_mode should be sent if SEND_IF_OFF is not set or is True + mqtt_mock.async_publish.reset_mock() + await common.async_set_swing_mode(hass, "on", ENTITY_CLIMATE) + mqtt_mock.async_publish.assert_has_calls(assert_async_publish) + + async def test_set_target_temperature(hass, mqtt_mock): """Test setting the target temperature.""" assert await async_setup_component(hass, CLIMATE_DOMAIN, DEFAULT_CONFIG) @@ -421,6 +495,45 @@ async def test_set_target_temperature(hass, mqtt_mock): mqtt_mock.async_publish.reset_mock() +# CONF_SEND_IF_OFF is deprecated, support will be removed with release 2022.9 +@pytest.mark.parametrize( + "send_if_off,assert_async_publish", + [ + ({}, [call("temperature-topic", "21.0", 0, False)]), + ({"send_if_off": True}, [call("temperature-topic", "21.0", 0, False)]), + ({"send_if_off": False}, []), + ], +) +async def test_set_target_temperature_send_if_off( + hass, mqtt_mock, send_if_off, assert_async_publish +): + """Test setting of target temperature if the hvac is off.""" + config = copy.deepcopy(DEFAULT_CONFIG) + config[CLIMATE_DOMAIN].update(send_if_off) + assert await async_setup_component(hass, CLIMATE_DOMAIN, config) + await hass.async_block_till_done() + assert hass.states.get(ENTITY_CLIMATE) is not None + + # Turn on HVAC + await common.async_set_hvac_mode(hass, "cool", ENTITY_CLIMATE) + mqtt_mock.async_publish.reset_mock() + # Updates for target temperature should be sent when the device is turned on + await common.async_set_temperature(hass, 16.0, ENTITY_CLIMATE) + mqtt_mock.async_publish.assert_called_once_with( + "temperature-topic", "16.0", 0, False + ) + + # Turn off HVAC + await common.async_set_hvac_mode(hass, "off", ENTITY_CLIMATE) + state = hass.states.get(ENTITY_CLIMATE) + assert state.state == "off" + + # Updates for target temperature sent should be if SEND_IF_OFF is not set or is True + mqtt_mock.async_publish.reset_mock() + await common.async_set_temperature(hass, 21.0, ENTITY_CLIMATE) + mqtt_mock.async_publish.assert_has_calls(assert_async_publish) + + async def test_set_target_temperature_pessimistic(hass, mqtt_mock): """Test setting the target temperature.""" config = copy.deepcopy(DEFAULT_CONFIG) -- GitLab