From b855f422efb0f8c3f9eb8fa89832232772db76cd Mon Sep 17 00:00:00 2001
From: Paulus Schoutsen <paulus@paulusschoutsen.nl>
Date: Thu, 23 Apr 2015 06:41:41 -0700
Subject: [PATCH] Tweak visibility config

---
 homeassistant/bootstrap.py      |  9 +++--
 homeassistant/const.py          |  1 +
 homeassistant/helpers/entity.py | 64 +++++++++++++-----------------
 tests/test_helper_entity.py     | 69 +++++++++++++++++++++++++++++++++
 4 files changed, 103 insertions(+), 40 deletions(-)
 create mode 100644 tests/test_helper_entity.py

diff --git a/homeassistant/bootstrap.py b/homeassistant/bootstrap.py
index 17e8cb3391b..ecd5be36dee 100644
--- a/homeassistant/bootstrap.py
+++ b/homeassistant/bootstrap.py
@@ -20,11 +20,11 @@ import homeassistant
 import homeassistant.loader as loader
 import homeassistant.components as core_components
 import homeassistant.components.group as group
-from homeassistant.helpers.entity import VisibilityABC
+from homeassistant.helpers.entity import Entity
 from homeassistant.const import (
     EVENT_COMPONENT_LOADED, CONF_LATITUDE, CONF_LONGITUDE,
-    CONF_TEMPERATURE_UNIT, CONF_NAME, CONF_TIME_ZONE, TEMP_CELCIUS,
-    TEMP_FAHRENHEIT)
+    CONF_TEMPERATURE_UNIT, CONF_NAME, CONF_TIME_ZONE, CONF_VISIBILITY,
+    TEMP_CELCIUS, TEMP_FAHRENHEIT)
 
 _LOGGER = logging.getLogger(__name__)
 
@@ -208,7 +208,8 @@ def process_ha_core_config(hass, config):
         if key in config:
             setattr(hass.config, attr, config[key])
 
-    VisibilityABC.visibility.update(config.get('visibility', {}))
+    for entity_id, hidden in config.get(CONF_VISIBILITY, {}).items():
+        Entity.overwrite_hidden(entity_id, hidden == 'hide')
 
     if CONF_TEMPERATURE_UNIT in config:
         unit = config[CONF_TEMPERATURE_UNIT]
diff --git a/homeassistant/const.py b/homeassistant/const.py
index a1aa0df40d1..0e859eaf943 100644
--- a/homeassistant/const.py
+++ b/homeassistant/const.py
@@ -11,6 +11,7 @@ CONF_LONGITUDE = "longitude"
 CONF_TEMPERATURE_UNIT = "temperature_unit"
 CONF_NAME = "name"
 CONF_TIME_ZONE = "time_zone"
+CONF_VISIBILITY = "visibility"
 
 CONF_PLATFORM = "platform"
 CONF_HOST = "host"
diff --git a/homeassistant/helpers/entity.py b/homeassistant/helpers/entity.py
index 07aaf9a234c..a39d46a29f6 100644
--- a/homeassistant/helpers/entity.py
+++ b/homeassistant/helpers/entity.py
@@ -11,45 +11,16 @@ from homeassistant.const import (
     ATTR_FRIENDLY_NAME, ATTR_UNIT_OF_MEASUREMENT, ATTR_HIDDEN, STATE_ON,
     STATE_OFF, DEVICE_DEFAULT_NAME, TEMP_CELCIUS, TEMP_FAHRENHEIT)
 
+# Dict mapping entity_id to a boolean that overwrites the hidden property
+_OVERWRITE_HIDDEN = {}
 
-class VisibilityABC(object):
-    """
-    Abstract Class for including visibility logic. This class includes the
-    necessary methods and properties to consider a visibility suggestion form
-    the component and then determine visibility based on the options in the
-    configuration file. When using this abstract class, the value for the
-    hidden property must still be included in the attributes disctionary. The
-    Entity class takes care of this automatically.
-    """
-    # pylint: disable=too-few-public-methods
 
-    entity_id = None
-    visibility = {}
-    _hidden = False
-
-    @property
-    def hidden(self):
-        """
-        Returns the official decision of whether the entity should be hidden.
-        Any value set by the user in the configuration file will overwrite
-        whatever the component sets for visibility.
-        """
-        if self.entity_id is not None and \
-                self.entity_id.lower() in self.visibility:
-            return self.visibility[self.entity_id.lower()] == 'hide'
-        else:
-            return self._hidden
-
-    @hidden.setter
-    def hidden(self, val):
-        """ Sets the suggestion for visibility. """
-        self._hidden = bool(val)
-
-
-class Entity(VisibilityABC):
+class Entity(object):
     """ ABC for Home Assistant entities. """
     # pylint: disable=no-self-use
 
+    _hidden = False
+
     # SAFE TO OVERWRITE
     # The properties and methods here are safe to overwrite when inherting this
     # class. These may be used to customize the behavior of the entity.
@@ -87,6 +58,16 @@ class Entity(VisibilityABC):
         """ Unit of measurement of this entity, if any. """
         return None
 
+    @property
+    def hidden(self):
+        """ Suggestion if the entity should be hidden from UIs. """
+        return self._hidden
+
+    @hidden.setter
+    def hidden(self, val):
+        """ Sets the suggestion for visibility. """
+        self._hidden = bool(val)
+
     def update(self):
         """ Retrieve latest state. """
         pass
@@ -140,8 +121,8 @@ class Entity(VisibilityABC):
         if ATTR_UNIT_OF_MEASUREMENT not in attr and self.unit_of_measurement:
             attr[ATTR_UNIT_OF_MEASUREMENT] = self.unit_of_measurement
 
-        if ATTR_HIDDEN not in attr:
-            attr[ATTR_HIDDEN] = bool(self.hidden)
+        if _OVERWRITE_HIDDEN.get(self.entity_id, self.hidden):
+            attr[ATTR_HIDDEN] = True
 
         # Convert temperature if we detect one
         if attr.get(ATTR_UNIT_OF_MEASUREMENT) in (TEMP_CELCIUS,
@@ -161,6 +142,17 @@ class Entity(VisibilityABC):
     def __repr__(self):
         return "<Entity {}: {}>".format(self.name, self.state)
 
+    @staticmethod
+    def overwrite_hidden(entity_id, hidden):
+        """
+        Overwrite the hidden property of an entity.
+        Set hidden to None to remove any overwritten value in place.
+        """
+        if hidden is None:
+            _OVERWRITE_HIDDEN.pop(entity_id, None)
+        else:
+            _OVERWRITE_HIDDEN[entity_id.lower()] = hidden
+
 
 class ToggleEntity(Entity):
     """ ABC for entities that can be turned on and off. """
diff --git a/tests/test_helper_entity.py b/tests/test_helper_entity.py
new file mode 100644
index 00000000000..9645bbc40c0
--- /dev/null
+++ b/tests/test_helper_entity.py
@@ -0,0 +1,69 @@
+"""
+tests.test_helper_entity
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+Tests the entity helper.
+"""
+# pylint: disable=protected-access,too-many-public-methods
+import unittest
+
+import homeassistant as ha
+import homeassistant.helpers.entity as entity
+from homeassistant.const import ATTR_HIDDEN
+
+
+class TestHelpersEntity(unittest.TestCase):
+    """ Tests homeassistant.helpers.entity module. """
+
+    def setUp(self):  # pylint: disable=invalid-name
+        """ Init needed objects. """
+        self.entity = entity.Entity()
+        self.entity.entity_id = 'test.overwrite_hidden_true'
+        self.hass = self.entity.hass = ha.HomeAssistant()
+
+    def tearDown(self):  # pylint: disable=invalid-name
+        """ Stop down stuff we started. """
+        self.hass.stop()
+
+    def test_default_hidden_not_in_attributes(self):
+        """ Test that the default hidden property is set to False. """
+        self.entity.update_ha_state()
+
+        self.assertNotIn(
+            ATTR_HIDDEN,
+            self.hass.states.get(self.entity.entity_id).attributes)
+
+    def test_setting_hidden_to_true(self):
+        self.entity.hidden = True
+        self.entity.update_ha_state()
+
+        state = self.hass.states.get(self.entity.entity_id)
+
+        self.assertTrue(state.attributes.get(ATTR_HIDDEN))
+
+        self.entity.hidden = False
+
+    def test_overwriting_hidden_property_to_true(self):
+        """ Test we can overwrite hidden property to True. """
+        entity.Entity.overwrite_hidden(self.entity.entity_id, True)
+
+        self.entity.update_ha_state()
+
+        state = self.hass.states.get(self.entity.entity_id)
+
+        self.assertTrue(state.attributes.get(ATTR_HIDDEN))
+
+        entity.Entity.overwrite_hidden(self.entity.entity_id, None)
+
+    def test_overwriting_hidden_property_to_false(self):
+        """ Test we can overwrite hidden property to True. """
+        entity.Entity.overwrite_hidden(self.entity.entity_id, False)
+
+        self.entity.hidden = True
+        self.entity.update_ha_state()
+
+        self.assertNotIn(
+            ATTR_HIDDEN,
+            self.hass.states.get(self.entity.entity_id).attributes)
+
+        entity.Entity.overwrite_hidden(self.entity.entity_id, None)
-- 
GitLab