From 3ddad83a84b260479a72627fce2521fbf6aec457 Mon Sep 17 00:00:00 2001 From: Otto Winter Date: Sat, 29 Sep 2018 20:54:57 +0200 Subject: [PATCH] Add unique_id to MQTT cover (#16950) * Add unique_id to MQTT cover * Fix tests --- homeassistant/components/cover/mqtt.py | 12 +++++- tests/components/cover/test_mqtt.py | 51 +++++++++++++++++++++----- 2 files changed, 52 insertions(+), 11 deletions(-) diff --git a/homeassistant/components/cover/mqtt.py b/homeassistant/components/cover/mqtt.py index a239f4cd4f8..cbc8fbee274 100644 --- a/homeassistant/components/cover/mqtt.py +++ b/homeassistant/components/cover/mqtt.py @@ -5,6 +5,7 @@ For more details about this platform, please refer to the documentation at https://home-assistant.io/components/cover.mqtt/ """ import logging +from typing import Optional import voluptuous as vol @@ -49,6 +50,7 @@ CONF_TILT_MIN = 'tilt_min' CONF_TILT_MAX = 'tilt_max' CONF_TILT_STATE_OPTIMISTIC = 'tilt_optimistic' CONF_TILT_INVERT_STATE = 'tilt_invert_state' +CONF_UNIQUE_ID = 'unique_id' DEFAULT_NAME = 'MQTT Cover' DEFAULT_PAYLOAD_OPEN = 'OPEN' @@ -93,6 +95,7 @@ PLATFORM_SCHEMA = mqtt.MQTT_BASE_PLATFORM_SCHEMA.extend({ default=DEFAULT_TILT_OPTIMISTIC): cv.boolean, vol.Optional(CONF_TILT_INVERT_STATE, default=DEFAULT_TILT_INVERT_STATE): cv.boolean, + vol.Optional(CONF_UNIQUE_ID): cv.string, }).extend(mqtt.MQTT_AVAILABILITY_SCHEMA.schema) @@ -151,6 +154,7 @@ async def _async_setup_entity(hass, config, async_add_entities, config.get(CONF_TILT_INVERT_STATE), config.get(CONF_POSITION_TOPIC), set_position_template, + config.get(CONF_UNIQUE_ID), discovery_hash )]) @@ -165,7 +169,7 @@ class MqttCover(MqttAvailability, MqttDiscoveryUpdate, CoverDevice): optimistic, value_template, tilt_open_position, tilt_closed_position, tilt_min, tilt_max, tilt_optimistic, tilt_invert, position_topic, set_position_template, - discovery_hash): + unique_id: Optional[str], discovery_hash): """Initialize the cover.""" MqttAvailability.__init__(self, availability_topic, qos, payload_available, payload_not_available) @@ -195,6 +199,7 @@ class MqttCover(MqttAvailability, MqttDiscoveryUpdate, CoverDevice): self._tilt_invert = tilt_invert self._position_topic = position_topic self._set_position_template = set_position_template + self._unique_id = unique_id self._discovery_hash = discovery_hash async def async_added_to_hass(self): @@ -412,3 +417,8 @@ class MqttCover(MqttAvailability, MqttDiscoveryUpdate, CoverDevice): if self._tilt_invert: position = self._tilt_max - position + offset return position + + @property + def unique_id(self): + """Return a unique ID.""" + return self._unique_id diff --git a/tests/components/cover/test_mqtt.py b/tests/components/cover/test_mqtt.py index b41a047e3db..355f620520a 100644 --- a/tests/components/cover/test_mqtt.py +++ b/tests/components/cover/test_mqtt.py @@ -11,11 +11,11 @@ from homeassistant.const import ( SERVICE_OPEN_COVER_TILT, SERVICE_SET_COVER_POSITION, SERVICE_SET_COVER_TILT_POSITION, SERVICE_STOP_COVER, STATE_CLOSED, STATE_OPEN, STATE_UNAVAILABLE, STATE_UNKNOWN) -from homeassistant.setup import setup_component +from homeassistant.setup import setup_component, async_setup_component from tests.common import ( get_test_home_assistant, mock_mqtt_component, async_fire_mqtt_message, - fire_mqtt_message, MockConfigEntry) + fire_mqtt_message, MockConfigEntry, async_mock_mqtt_component) class TestCoverMQTT(unittest.TestCase): @@ -614,7 +614,8 @@ class TestCoverMQTT(unittest.TestCase): 'cover.test', 'state-topic', 'command-topic', None, 'tilt-command-topic', 'tilt-status-topic', 0, False, 'OPEN', 'CLOSE', 'OPEN', 'CLOSE', 'STOP', None, None, - False, None, 100, 0, 0, 100, False, False, None, None, None) + False, None, 100, 0, 0, 100, False, False, None, None, None, + None) self.assertEqual(44, mqtt_cover.find_percentage_in_range(44)) @@ -624,7 +625,8 @@ class TestCoverMQTT(unittest.TestCase): 'cover.test', 'state-topic', 'command-topic', None, 'tilt-command-topic', 'tilt-status-topic', 0, False, 'OPEN', 'CLOSE', 'OPEN', 'CLOSE', 'STOP', None, None, - False, None, 180, 80, 80, 180, False, False, None, None, None) + False, None, 180, 80, 80, 180, False, False, None, None, None, + None) self.assertEqual(40, mqtt_cover.find_percentage_in_range(120)) @@ -634,7 +636,8 @@ class TestCoverMQTT(unittest.TestCase): 'cover.test', 'state-topic', 'command-topic', None, 'tilt-command-topic', 'tilt-status-topic', 0, False, 'OPEN', 'CLOSE', 'OPEN', 'CLOSE', 'STOP', None, None, - False, None, 100, 0, 0, 100, False, True, None, None, None) + False, None, 100, 0, 0, 100, False, True, None, None, None, + None) self.assertEqual(56, mqtt_cover.find_percentage_in_range(44)) @@ -644,7 +647,8 @@ class TestCoverMQTT(unittest.TestCase): 'cover.test', 'state-topic', 'command-topic', None, 'tilt-command-topic', 'tilt-status-topic', 0, False, 'OPEN', 'CLOSE', 'OPEN', 'CLOSE', 'STOP', None, None, - False, None, 180, 80, 80, 180, False, True, None, None, None) + False, None, 180, 80, 80, 180, False, True, None, None, None, + None) self.assertEqual(60, mqtt_cover.find_percentage_in_range(120)) @@ -654,7 +658,8 @@ class TestCoverMQTT(unittest.TestCase): 'cover.test', 'state-topic', 'command-topic', None, 'tilt-command-topic', 'tilt-status-topic', 0, False, 'OPEN', 'CLOSE', 'OPEN', 'CLOSE', 'STOP', None, None, - False, None, 100, 0, 0, 100, False, False, None, None, None) + False, None, 100, 0, 0, 100, False, False, None, None, None, + None) self.assertEqual(44, mqtt_cover.find_in_range_from_percent(44)) @@ -664,7 +669,8 @@ class TestCoverMQTT(unittest.TestCase): 'cover.test', 'state-topic', 'command-topic', None, 'tilt-command-topic', 'tilt-status-topic', 0, False, 'OPEN', 'CLOSE', 'OPEN', 'CLOSE', 'STOP', None, None, - False, None, 180, 80, 80, 180, False, False, None, None, None) + False, None, 180, 80, 80, 180, False, False, None, None, None, + None) self.assertEqual(120, mqtt_cover.find_in_range_from_percent(40)) @@ -674,7 +680,8 @@ class TestCoverMQTT(unittest.TestCase): 'cover.test', 'state-topic', 'command-topic', None, 'tilt-command-topic', 'tilt-status-topic', 0, False, 'OPEN', 'CLOSE', 'OPEN', 'CLOSE', 'STOP', None, None, - False, None, 100, 0, 0, 100, False, True, None, None, None) + False, None, 100, 0, 0, 100, False, True, None, None, None, + None) self.assertEqual(44, mqtt_cover.find_in_range_from_percent(56)) @@ -684,7 +691,8 @@ class TestCoverMQTT(unittest.TestCase): 'cover.test', 'state-topic', 'command-topic', None, 'tilt-command-topic', 'tilt-status-topic', 0, False, 'OPEN', 'CLOSE', 'OPEN', 'CLOSE', 'STOP', None, None, - False, None, 180, 80, 80, 180, False, True, None, None, None) + False, None, 180, 80, 80, 180, False, True, None, None, None, + None) self.assertEqual(120, mqtt_cover.find_in_range_from_percent(60)) @@ -779,3 +787,26 @@ async def test_discovery_removal_cover(hass, mqtt_mock, caplog): await hass.async_block_till_done() state = hass.states.get('cover.beer') assert state is None + + +async def test_unique_id(hass): + """Test unique_id option only creates one cover per id.""" + await async_mock_mqtt_component(hass) + assert await async_setup_component(hass, cover.DOMAIN, { + cover.DOMAIN: [{ + 'platform': 'mqtt', + 'name': 'Test 1', + 'state_topic': 'test-topic', + 'unique_id': 'TOTALLY_UNIQUE' + }, { + 'platform': 'mqtt', + 'name': 'Test 2', + 'state_topic': 'test-topic', + 'unique_id': 'TOTALLY_UNIQUE' + }] + }) + + async_fire_mqtt_message(hass, 'test-topic', 'payload') + await hass.async_block_till_done() + + assert len(hass.states.async_entity_ids(cover.DOMAIN)) == 1