From 72a1b7ae3fc5340b44c7978ae6d1551c47aef4d7 Mon Sep 17 00:00:00 2001
From: Julian Knauer <jpk@goatpr0n.de>
Date: Tue, 22 May 2018 09:25:10 +0200
Subject: [PATCH] Lagute LW-12 Wifi LED control (#13307)

* Added platform lw12wifi for Lagute LW-12 Wifi Lights

Supported features:
* RGB colors
* Variable brightness
* 29 effects
* Changing transitions speed for animated effects

* Added lw12wifi to the list of omitted files to test

* Added lw12 module as new requirement for lw12wifi platform

* Added configuration example docstring for platform lw12wifi

* Updating code according to review in PR:

* Removed unused imports: enum, socket.
* Unused and not imported feature SUPPORT_FLASH was removed.
* Unused import lw12 in setup_platform method removed.
* Fixed indention for valuptuous.
* Changed check if effect is None.
* Removed personal debug output.
* Blocking function are not async anymore.

* Further improvements to satisfy PR.

* Unused import asyncio removed.
* Fixed: Return value and docstring no match up for `assumed_state`.

* Check if the set effect is supported, otherwise revert to normal light.

* Added describing missing docstrings to all functions.

* Adopted code to work with HS color setting.

* Syntactical change in comment.

* Removed redefinition of DOMAIN.

* Refactored lw12 controller setup: removed requirement for host and port in LW12Wifi class.

* Rewritten supported feature setup to a more static  expression.

* Removed unused rgb_color property

* Fixed typo in comment for set_light_option

* Changed RGB option validation schema

* Removed instance properties as config options

* Removed optional settings to be more inline with code style.

* Removed unused option from config example

* Removal of unused import

* Added property to disable state polling for this entity.

* Raise an exception if an unknown effect was selected.

* Fixed an issue with the check for known effects.

* As we do not need to set a default, use simple accessing by key.

* Log if an unknown effect was selected.

* Added link to future documentation.
---
 .coveragerc                                |   1 +
 homeassistant/components/light/lw12wifi.py | 158 +++++++++++++++++++++
 requirements_all.txt                       |   3 +
 3 files changed, 162 insertions(+)
 create mode 100644 homeassistant/components/light/lw12wifi.py

diff --git a/.coveragerc b/.coveragerc
index d361cf2ddad..a31af5f296c 100644
--- a/.coveragerc
+++ b/.coveragerc
@@ -443,6 +443,7 @@ omit =
     homeassistant/components/light/lifx_legacy.py
     homeassistant/components/light/lifx.py
     homeassistant/components/light/limitlessled.py
+    homeassistant/components/light/lw12wifi.py
     homeassistant/components/light/mystrom.py
     homeassistant/components/light/nanoleaf_aurora.py
     homeassistant/components/light/osramlightify.py
diff --git a/homeassistant/components/light/lw12wifi.py b/homeassistant/components/light/lw12wifi.py
new file mode 100644
index 00000000000..f81d8368f98
--- /dev/null
+++ b/homeassistant/components/light/lw12wifi.py
@@ -0,0 +1,158 @@
+"""
+Support for Lagute LW-12 WiFi LED Controller.
+
+For more details about this platform, please refer to the documentation at
+https://home-assistant.io/components/light.lw12wifi/
+"""
+
+import logging
+
+import voluptuous as vol
+
+from homeassistant.components.light import (
+    ATTR_BRIGHTNESS, ATTR_EFFECT, ATTR_HS_COLOR, ATTR_TRANSITION,
+    Light, PLATFORM_SCHEMA, SUPPORT_BRIGHTNESS, SUPPORT_EFFECT,
+    SUPPORT_COLOR, SUPPORT_TRANSITION
+)
+from homeassistant.const import (
+    CONF_HOST, CONF_NAME, CONF_PORT
+)
+import homeassistant.helpers.config_validation as cv
+import homeassistant.util.color as color_util
+
+
+REQUIREMENTS = ['lw12==0.9.2']
+
+_LOGGER = logging.getLogger(__name__)
+
+
+DEFAULT_NAME = 'LW-12 FC'
+DEFAULT_PORT = 5000
+
+PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
+    vol.Required(CONF_HOST): cv.string,
+    vol.Optional(CONF_PORT, default=DEFAULT_PORT): cv.port,
+    vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
+})
+
+
+def setup_platform(hass, config, add_devices, discovery_info=None):
+    """Setup LW-12 WiFi LED Controller platform."""
+    import lw12
+
+    # Assign configuration variables.
+    name = config.get(CONF_NAME)
+    host = config.get(CONF_HOST)
+    port = config.get(CONF_PORT)
+    # Add devices
+    lw12_light = lw12.LW12Controller(host, port)
+    add_devices([LW12WiFi(name, lw12_light)])
+
+
+class LW12WiFi(Light):
+    """LW-12 WiFi LED Controller."""
+
+    def __init__(self, name, lw12_light):
+        """Initialisation of LW-12 WiFi LED Controller.
+
+        Args:
+            name: Friendly name for this platform to use.
+            lw12_light: Instance of the LW12 controller.
+        """
+        self._light = lw12_light
+        self._name = name
+        self._state = None
+        self._effect = None
+        self._rgb_color = [255, 255, 255]
+        self._brightness = 255
+        # Setup feature list
+        self._supported_features = SUPPORT_BRIGHTNESS | SUPPORT_EFFECT \
+            | SUPPORT_COLOR | SUPPORT_TRANSITION
+
+    @property
+    def name(self):
+        """Return the display name of the controlled light."""
+        return self._name
+
+    @property
+    def brightness(self):
+        """Return the brightness of the light."""
+        return self._brightness
+
+    @property
+    def hs_color(self):
+        """Read back the hue-saturation of the light."""
+        return color_util.color_RGB_to_hs(*self._rgb_color)
+
+    @property
+    def effect(self):
+        """Return current light effect."""
+        if self._effect is None:
+            return None
+        return self._effect.replace('_', ' ').title()
+
+    @property
+    def is_on(self):
+        """Return true if light is on."""
+        return self._state
+
+    @property
+    def supported_features(self):
+        """Return a list of supported features."""
+        return self._supported_features
+
+    @property
+    def effect_list(self):
+        """Return a list of available effects.
+
+        Use the Enum element name for display.
+        """
+        import lw12
+        return [effect.name.replace('_', ' ').title()
+                for effect in lw12.LW12_EFFECT]
+
+    @property
+    def assumed_state(self) -> bool:
+        """Return True if unable to access real state of the entity."""
+        return True
+
+    @property
+    def shoud_poll(self) -> bool:
+        """Return False to not poll the state of this entity."""
+        return False
+
+    def turn_on(self, **kwargs):
+        """Instruct the light to turn on."""
+        import lw12
+        self._light.light_on()
+        if ATTR_HS_COLOR in kwargs:
+            self._rgb_color = color_util.color_hs_to_RGB(
+                *kwargs[ATTR_HS_COLOR])
+            self._light.set_color(*self._rgb_color)
+            self._effect = None
+        if ATTR_BRIGHTNESS in kwargs:
+            self._brightness = kwargs.get(ATTR_BRIGHTNESS)
+            brightness = int(self._brightness / 255 * 100)
+            self._light.set_light_option(lw12.LW12_LIGHT.BRIGHTNESS,
+                                         brightness)
+        if ATTR_EFFECT in kwargs:
+            self._effect = kwargs[ATTR_EFFECT].replace(' ', '_').upper()
+            # Check if a known and supported effect was selected.
+            if self._effect in [eff.name for eff in lw12.LW12_EFFECT]:
+                # Selected effect is supported and will be applied.
+                self._light.set_effect(lw12.LW12_EFFECT[self._effect])
+            else:
+                # Unknown effect was set, recover by disabling the effect
+                # mode and log an error.
+                _LOGGER.error("Unknown effect selected: %s", self._effect)
+                self._effect = None
+        if ATTR_TRANSITION in kwargs:
+            transition_speed = int(kwargs[ATTR_TRANSITION])
+            self._light.set_light_option(lw12.LW12_LIGHT.FLASH,
+                                         transition_speed)
+        self._state = True
+
+    def turn_off(self, **kwargs):
+        """Instruct the light to turn off."""
+        self._light.light_off()
+        self._state = False
diff --git a/requirements_all.txt b/requirements_all.txt
index ef0aa86ee6b..016e2f9ce2d 100644
--- a/requirements_all.txt
+++ b/requirements_all.txt
@@ -514,6 +514,9 @@ locationsharinglib==2.0.2
 # homeassistant.components.sensor.luftdaten
 luftdaten==0.1.3
 
+# homeassistant.components.light.lw12wifi
+lw12==0.9.2
+
 # homeassistant.components.sensor.lyft
 lyft_rides==0.2
 
-- 
GitLab