From 2d011821ea0e452c9e86a7107632650c9e018cdd Mon Sep 17 00:00:00 2001 From: Jan Bouwhuis Date: Thu, 3 Feb 2022 16:49:09 +0100 Subject: [PATCH] Add MQTT humidifier unknown state support (#65302) * Add MQTT humidifier unknown state support * Update homeassistant/components/mqtt/humidifier.py Co-authored-by: Erik Montnemery * Fix tests for changed default optimistic state Co-authored-by: Erik Montnemery --- homeassistant/components/mqtt/humidifier.py | 8 +++++-- tests/components/mqtt/test_humidifier.py | 23 ++++++++++++++------- 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/homeassistant/components/mqtt/humidifier.py b/homeassistant/components/mqtt/humidifier.py index b2c4ed4b916..e5f4cea6f88 100644 --- a/homeassistant/components/mqtt/humidifier.py +++ b/homeassistant/components/mqtt/humidifier.py @@ -66,6 +66,8 @@ DEFAULT_PAYLOAD_ON = "ON" DEFAULT_PAYLOAD_OFF = "OFF" DEFAULT_PAYLOAD_RESET = "None" +PAYLOAD_NONE = "None" + MQTT_HUMIDIFIER_ATTRIBUTES_BLOCKED = frozenset( { humidifier.ATTR_HUMIDITY, @@ -187,7 +189,7 @@ class MqttHumidifier(MqttEntity, HumidifierEntity): def __init__(self, hass, config, config_entry, discovery_data): """Initialize the MQTT humidifier.""" - self._state = False + self._state = None self._target_humidity = None self._mode = None self._supported_features = 0 @@ -283,6 +285,8 @@ class MqttHumidifier(MqttEntity, HumidifierEntity): self._state = True elif payload == self._payload["STATE_OFF"]: self._state = False + elif payload == PAYLOAD_NONE: + self._state = None self.async_write_ha_state() if self._topic[CONF_STATE_TOPIC] is not None: @@ -392,7 +396,7 @@ class MqttHumidifier(MqttEntity, HumidifierEntity): return self._available_modes @property - def is_on(self): + def is_on(self) -> bool | None: """Return true if device is on.""" return self._state diff --git a/tests/components/mqtt/test_humidifier.py b/tests/components/mqtt/test_humidifier.py index 62d29c12ee8..48fe5b29a0c 100644 --- a/tests/components/mqtt/test_humidifier.py +++ b/tests/components/mqtt/test_humidifier.py @@ -28,6 +28,7 @@ from homeassistant.const import ( SERVICE_TURN_ON, STATE_OFF, STATE_ON, + STATE_UNKNOWN, ) from homeassistant.setup import async_setup_component @@ -157,7 +158,7 @@ async def test_controlling_state_via_topic(hass, mqtt_mock, caplog): await hass.async_block_till_done() state = hass.states.get("humidifier.test") - assert state.state == STATE_OFF + assert state.state == STATE_UNKNOWN assert not state.attributes.get(ATTR_ASSUMED_STATE) async_fire_mqtt_message(hass, "state-topic", "StAtE_On") @@ -220,6 +221,10 @@ async def test_controlling_state_via_topic(hass, mqtt_mock, caplog): state = hass.states.get("humidifier.test") assert state.attributes.get(humidifier.ATTR_HUMIDITY) is None + async_fire_mqtt_message(hass, "state-topic", "None") + state = hass.states.get("humidifier.test") + assert state.state == STATE_UNKNOWN + async def test_controlling_state_via_topic_and_json_message(hass, mqtt_mock, caplog): """Test the controlling state via topic and JSON message.""" @@ -250,7 +255,7 @@ async def test_controlling_state_via_topic_and_json_message(hass, mqtt_mock, cap await hass.async_block_till_done() state = hass.states.get("humidifier.test") - assert state.state == STATE_OFF + assert state.state == STATE_UNKNOWN assert not state.attributes.get(ATTR_ASSUMED_STATE) async_fire_mqtt_message(hass, "state-topic", '{"val":"ON"}') @@ -301,6 +306,10 @@ async def test_controlling_state_via_topic_and_json_message(hass, mqtt_mock, cap assert "Ignoring empty mode from" in caplog.text caplog.clear() + async_fire_mqtt_message(hass, "state-topic", '{"val": null}') + state = hass.states.get("humidifier.test") + assert state.state == STATE_UNKNOWN + async def test_controlling_state_via_topic_and_json_message_shared_topic( hass, mqtt_mock, caplog @@ -333,7 +342,7 @@ async def test_controlling_state_via_topic_and_json_message_shared_topic( await hass.async_block_till_done() state = hass.states.get("humidifier.test") - assert state.state == STATE_OFF + assert state.state == STATE_UNKNOWN assert not state.attributes.get(ATTR_ASSUMED_STATE) async_fire_mqtt_message( @@ -404,7 +413,7 @@ async def test_sending_mqtt_commands_and_optimistic(hass, mqtt_mock, caplog): await hass.async_block_till_done() state = hass.states.get("humidifier.test") - assert state.state == STATE_OFF + assert state.state == STATE_UNKNOWN assert state.attributes.get(ATTR_ASSUMED_STATE) await async_turn_on(hass, "humidifier.test") @@ -498,7 +507,7 @@ async def test_sending_mqtt_command_templates_(hass, mqtt_mock, caplog): await hass.async_block_till_done() state = hass.states.get("humidifier.test") - assert state.state == STATE_OFF + assert state.state == STATE_UNKNOWN assert state.attributes.get(ATTR_ASSUMED_STATE) await async_turn_on(hass, "humidifier.test") @@ -593,7 +602,7 @@ async def test_sending_mqtt_commands_and_explicit_optimistic(hass, mqtt_mock, ca await hass.async_block_till_done() state = hass.states.get("humidifier.test") - assert state.state == STATE_OFF + assert state.state == STATE_UNKNOWN assert state.attributes.get(ATTR_ASSUMED_STATE) await async_turn_on(hass, "humidifier.test") @@ -731,7 +740,7 @@ async def test_attributes(hass, mqtt_mock, caplog): await hass.async_block_till_done() state = hass.states.get("humidifier.test") - assert state.state == STATE_OFF + assert state.state == STATE_UNKNOWN assert state.attributes.get(humidifier.ATTR_AVAILABLE_MODES) == [ "eco", "baby",