diff --git a/homeassistant/components/cover/mqtt.py b/homeassistant/components/cover/mqtt.py index 235b28b5be2..f51cca8a276 100644 --- a/homeassistant/components/cover/mqtt.py +++ b/homeassistant/components/cover/mqtt.py @@ -279,21 +279,19 @@ class MqttCover(MqttAvailability, MqttDiscoveryUpdate, MqttEntityDeviceInfo, if self._template is not None: payload = self._template.async_render_with_possible_json_value( payload) + if payload.isnumeric(): - if 0 <= int(payload) <= 100: - percentage_payload = int(payload) - else: - percentage_payload = self.find_percentage_in_range( - float(payload), COVER_PAYLOAD) - if 0 <= percentage_payload <= 100: - self._position = percentage_payload - self._state = self._position == self._position_closed + percentage_payload = self.find_percentage_in_range( + float(payload), COVER_PAYLOAD) + self._position = percentage_payload + self._state = percentage_payload == DEFAULT_POSITION_CLOSED else: _LOGGER.warning( "Payload is not integer within range: %s", payload) return self.async_schedule_update_ha_state() + if self._get_position_topic: await mqtt.async_subscribe( self.hass, self._get_position_topic, @@ -374,7 +372,8 @@ class MqttCover(MqttAvailability, MqttDiscoveryUpdate, MqttEntityDeviceInfo, # Optimistically assume that cover has changed state. self._state = False if self._get_position_topic: - self._position = self._position_open + self._position = self.find_percentage_in_range( + self._position_open, COVER_PAYLOAD) self.async_schedule_update_ha_state() async def async_close_cover(self, **kwargs): @@ -389,7 +388,8 @@ class MqttCover(MqttAvailability, MqttDiscoveryUpdate, MqttEntityDeviceInfo, # Optimistically assume that cover has changed state. self._state = True if self._get_position_topic: - self._position = self._position_closed + self._position = self.find_percentage_in_range( + self._position_closed, COVER_PAYLOAD) self.async_schedule_update_ha_state() async def async_stop_cover(self, **kwargs): @@ -469,6 +469,11 @@ class MqttCover(MqttAvailability, MqttDiscoveryUpdate, MqttEntityDeviceInfo, offset_position = position - min_range position_percentage = round( float(offset_position) / current_range * 100.0) + + max_percent = 100 + min_percent = 0 + position_percentage = min(max(position_percentage, min_percent), + max_percent) if range_type == TILT_PAYLOAD and self._tilt_invert: return 100 - position_percentage return position_percentage diff --git a/tests/components/cover/test_mqtt.py b/tests/components/cover/test_mqtt.py index 81c0848c4c5..26204ce6ebd 100644 --- a/tests/components/cover/test_mqtt.py +++ b/tests/components/cover/test_mqtt.py @@ -308,18 +308,81 @@ class TestCoverMQTT(unittest.TestCase): 'cover.test').attributes['current_position'] assert 50 == current_cover_position - fire_mqtt_message(self.hass, 'get-position-topic', '101') - self.hass.block_till_done() - current_cover_position = self.hass.states.get( - 'cover.test').attributes['current_position'] - assert 50 == current_cover_position - fire_mqtt_message(self.hass, 'get-position-topic', 'non-numeric') self.hass.block_till_done() current_cover_position = self.hass.states.get( 'cover.test').attributes['current_position'] assert 50 == current_cover_position + fire_mqtt_message(self.hass, 'get-position-topic', '101') + self.hass.block_till_done() + current_cover_position = self.hass.states.get( + 'cover.test').attributes['current_position'] + assert 100 == current_cover_position + + def test_current_cover_position_inverted(self): + """Test the current cover position.""" + assert setup_component(self.hass, cover.DOMAIN, { + cover.DOMAIN: { + 'platform': 'mqtt', + 'name': 'test', + 'position_topic': 'get-position-topic', + 'command_topic': 'command-topic', + 'position_open': 0, + 'position_closed': 100, + 'payload_open': 'OPEN', + 'payload_close': 'CLOSE', + 'payload_stop': 'STOP' + } + }) + + state_attributes_dict = self.hass.states.get( + 'cover.test').attributes + assert not ('current_position' in state_attributes_dict) + assert not ('current_tilt_position' in state_attributes_dict) + assert not (4 & self.hass.states.get( + 'cover.test').attributes['supported_features'] == 4) + + fire_mqtt_message(self.hass, 'get-position-topic', '100') + self.hass.block_till_done() + current_percentage_cover_position = self.hass.states.get( + 'cover.test').attributes['current_position'] + assert 0 == current_percentage_cover_position + assert STATE_CLOSED == self.hass.states.get( + 'cover.test').state + + fire_mqtt_message(self.hass, 'get-position-topic', '0') + self.hass.block_till_done() + current_percentage_cover_position = self.hass.states.get( + 'cover.test').attributes['current_position'] + assert 100 == current_percentage_cover_position + assert STATE_OPEN == self.hass.states.get( + 'cover.test').state + + fire_mqtt_message(self.hass, 'get-position-topic', '50') + self.hass.block_till_done() + current_percentage_cover_position = self.hass.states.get( + 'cover.test').attributes['current_position'] + assert 50 == current_percentage_cover_position + assert STATE_OPEN == self.hass.states.get( + 'cover.test').state + + fire_mqtt_message(self.hass, 'get-position-topic', 'non-numeric') + self.hass.block_till_done() + current_percentage_cover_position = self.hass.states.get( + 'cover.test').attributes['current_position'] + assert 50 == current_percentage_cover_position + assert STATE_OPEN == self.hass.states.get( + 'cover.test').state + + fire_mqtt_message(self.hass, 'get-position-topic', '101') + self.hass.block_till_done() + current_percentage_cover_position = self.hass.states.get( + 'cover.test').attributes['current_position'] + assert 0 == current_percentage_cover_position + assert STATE_CLOSED == self.hass.states.get( + 'cover.test').state + def test_set_cover_position(self): """Test setting cover position.""" assert setup_component(self.hass, cover.DOMAIN, {