From a99b4472a8bfa63edf774765db3f1d1aecd57cdf Mon Sep 17 00:00:00 2001
From: Juha Niemi <juha.niemi@wunder.io>
Date: Fri, 27 Jul 2018 12:11:32 +0300
Subject: [PATCH] Add support for P5 FutureNow light platform (#15662)

* Added support for FutureNow light platform and relay/dimmer units

* Pinned specific version for requirement

* Added support for FutureNow light platform and relay/dimmer units

* Added futurenow.py to .coveragerc.

* Minor fixes and enhancements as requested in the code review.

* Minor fixes and enhancements as requested in the code review.

* Use device_config's value directly as it's validated as boolean.

* Simplify state check.

* Fixed brightness update that was broken in previous commit.
---
 .coveragerc                                 |   1 +
 homeassistant/components/light/futurenow.py | 135 ++++++++++++++++++++
 requirements_all.txt                        |   3 +
 3 files changed, 139 insertions(+)
 create mode 100644 homeassistant/components/light/futurenow.py

diff --git a/.coveragerc b/.coveragerc
index 7e10830d876..84f4da0e371 100644
--- a/.coveragerc
+++ b/.coveragerc
@@ -465,6 +465,7 @@ omit =
     homeassistant/components/light/decora_wifi.py
     homeassistant/components/light/decora.py
     homeassistant/components/light/flux_led.py
+    homeassistant/components/light/futurenow.py
     homeassistant/components/light/greenwave.py
     homeassistant/components/light/hue.py
     homeassistant/components/light/hyperion.py
diff --git a/homeassistant/components/light/futurenow.py b/homeassistant/components/light/futurenow.py
new file mode 100644
index 00000000000..56ecaa7b2ca
--- /dev/null
+++ b/homeassistant/components/light/futurenow.py
@@ -0,0 +1,135 @@
+"""
+Support for FutureNow Ethernet unit outputs as Lights.
+
+For more details about this platform, please refer to the documentation at
+https://home-assistant.io/components/light.futurenow/
+"""
+
+import logging
+
+import voluptuous as vol
+
+from homeassistant.const import (
+    CONF_NAME, CONF_HOST, CONF_PORT, CONF_DEVICES)
+from homeassistant.components.light import (
+    ATTR_BRIGHTNESS, SUPPORT_BRIGHTNESS, Light,
+    PLATFORM_SCHEMA)
+import homeassistant.helpers.config_validation as cv
+
+REQUIREMENTS = ['pyfnip==0.1']
+
+_LOGGER = logging.getLogger(__name__)
+
+CONF_DRIVER = 'driver'
+CONF_DRIVER_FNIP6X10AD = 'FNIP6x10ad'
+CONF_DRIVER_FNIP8X10A = 'FNIP8x10a'
+CONF_DRIVER_TYPES = [CONF_DRIVER_FNIP6X10AD, CONF_DRIVER_FNIP8X10A]
+
+DEVICE_SCHEMA = vol.Schema({
+    vol.Required(CONF_NAME): cv.string,
+    vol.Optional('dimmable', default=False): cv.boolean,
+})
+
+PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
+    vol.Required(CONF_DRIVER): vol.In(CONF_DRIVER_TYPES),
+    vol.Required(CONF_HOST): cv.string,
+    vol.Required(CONF_PORT): cv.port,
+    vol.Required(CONF_DEVICES): {cv.string: DEVICE_SCHEMA},
+})
+
+
+def setup_platform(hass, config, add_devices, discovery_info=None):
+    """Set up the light platform for each FutureNow unit."""
+    lights = []
+    for channel, device_config in config[CONF_DEVICES].items():
+        device = {}
+        device['name'] = device_config[CONF_NAME]
+        device['dimmable'] = device_config['dimmable']
+        device['channel'] = channel
+        device['driver'] = config[CONF_DRIVER]
+        device['host'] = config[CONF_HOST]
+        device['port'] = config[CONF_PORT]
+        lights.append(FutureNowLight(device))
+
+    add_devices(lights, True)
+
+
+def to_futurenow_level(level):
+    """Convert the given HASS light level (0-255) to FutureNow (0-100)."""
+    return int((level * 100) / 255)
+
+
+def to_hass_level(level):
+    """Convert the given FutureNow (0-100) light level to HASS (0-255)."""
+    return int((level * 255) / 100)
+
+
+class FutureNowLight(Light):
+    """Representation of an FutureNow light."""
+
+    def __init__(self, device):
+        """Initialize the light."""
+        import pyfnip
+
+        self._name = device['name']
+        self._dimmable = device['dimmable']
+        self._channel = device['channel']
+        self._brightness = None
+        self._state = None
+        self._skip_update = False
+
+        if device['driver'] == CONF_DRIVER_FNIP6X10AD:
+            self._light = pyfnip.FNIP6x2adOutput(device['host'],
+                                                 device['port'],
+                                                 self._channel)
+        if device['driver'] == CONF_DRIVER_FNIP8X10A:
+            self._light = pyfnip.FNIP8x10aOutput(device['host'],
+                                                 device['port'],
+                                                 self._channel)
+
+    @property
+    def name(self):
+        """Return the name of the device if any."""
+        return self._name
+
+    @property
+    def is_on(self):
+        """Return true if device is on."""
+        return self._state
+
+    @property
+    def brightness(self):
+        """Return the brightness of this light between 0..255."""
+        return self._brightness
+
+    @property
+    def supported_features(self):
+        """Flag supported features."""
+        if self._dimmable:
+            return SUPPORT_BRIGHTNESS
+        return 0
+
+    def turn_on(self, **kwargs):
+        """Turn the light on."""
+        level = kwargs.get(ATTR_BRIGHTNESS, 255) if self._dimmable else 255
+        self._light.turn_on(to_futurenow_level(level))
+        self._brightness = level
+        self._state = True
+        self._skip_update = True
+
+    def turn_off(self, **kwargs):
+        """Turn the light off."""
+        self._light.turn_off()
+        self._brightness = 0
+        self._state = False
+        self._skip_update = True
+
+    def update(self):
+        """Fetch new state data for this light."""
+        if self._skip_update:
+            self._skip_update = False
+            return
+
+        state = int(self._light.is_on())
+        self._state = bool(state)
+        self._brightness = to_hass_level(state)
diff --git a/requirements_all.txt b/requirements_all.txt
index 3b89719651f..51ab8100372 100644
--- a/requirements_all.txt
+++ b/requirements_all.txt
@@ -825,6 +825,9 @@ pyflexit==0.3
 # homeassistant.components.binary_sensor.flic
 pyflic-homeassistant==0.4.dev0
 
+# homeassistant.components.light.futurenow
+pyfnip==0.1
+
 # homeassistant.components.fritzbox
 pyfritzhome==0.3.7
 
-- 
GitLab