Skip to content

Commit

Permalink
Add EverLights light component (home-assistant#19817)
Browse files Browse the repository at this point in the history
* EverLights light integration. Supports single color (with color and brightness parameters) or saved pattern (with effect parameter).

* Fix pylint parameter name warning.

* Code review feedback.

* Add tests for the two helper functions of EverLights component.

* Fixes for review feedback.

* Change test style.

* Style fixes for hound.
  • Loading branch information
joncar authored and MartinHjelmare committed Jan 21, 2019
1 parent 5999df1 commit 9482a63
Show file tree
Hide file tree
Showing 4 changed files with 197 additions and 0 deletions.
1 change: 1 addition & 0 deletions .coveragerc
Original file line number Diff line number Diff line change
Expand Up @@ -581,6 +581,7 @@ omit =
homeassistant/components/light/blinkt.py
homeassistant/components/light/decora_wifi.py
homeassistant/components/light/decora.py
homeassistant/components/light/everlights.py
homeassistant/components/light/flux_led.py
homeassistant/components/light/futurenow.py
homeassistant/components/light/greenwave.py
Expand Down
177 changes: 177 additions & 0 deletions homeassistant/components/light/everlights.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
"""
Support for EverLights lights.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/light.everlights/
"""
import logging
from datetime import timedelta
from typing import Tuple

import voluptuous as vol

from homeassistant.const import CONF_HOSTS
from homeassistant.components.light import (
ATTR_BRIGHTNESS, ATTR_HS_COLOR, ATTR_EFFECT,
SUPPORT_BRIGHTNESS, SUPPORT_EFFECT, SUPPORT_COLOR,
Light, PLATFORM_SCHEMA)
import homeassistant.helpers.config_validation as cv
import homeassistant.util.color as color_util
from homeassistant.helpers.aiohttp_client import async_get_clientsession
from homeassistant.exceptions import PlatformNotReady

REQUIREMENTS = ['pyeverlights==0.1.0']

_LOGGER = logging.getLogger(__name__)

SUPPORT_EVERLIGHTS = (SUPPORT_EFFECT | SUPPORT_BRIGHTNESS | SUPPORT_COLOR)

SCAN_INTERVAL = timedelta(minutes=1)

PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Required(CONF_HOSTS): vol.All(cv.ensure_list, [cv.string]),
})

NAME_FORMAT = "EverLights {} Zone {}"


def color_rgb_to_int(red: int, green: int, blue: int) -> int:
"""Return a RGB color as an integer."""
return red*256*256+green*256+blue


def color_int_to_rgb(value: int) -> Tuple[int, int, int]:
"""Return an RGB tuple from an integer."""
return (value >> 16, (value >> 8) & 0xff, value & 0xff)


async def async_setup_platform(hass, config, async_add_entities,
discovery_info=None):
"""Set up the EverLights lights from configuration.yaml."""
import pyeverlights
lights = []

for ipaddr in config[CONF_HOSTS]:
api = pyeverlights.EverLights(ipaddr,
async_get_clientsession(hass))

try:
status = await api.get_status()

effects = await api.get_all_patterns()

except pyeverlights.ConnectionError:
raise PlatformNotReady

else:
lights.append(EverLightsLight(api, pyeverlights.ZONE_1,
status, effects))
lights.append(EverLightsLight(api, pyeverlights.ZONE_2,
status, effects))

async_add_entities(lights)


class EverLightsLight(Light):
"""Representation of a Flux light."""

def __init__(self, api, channel, status, effects):
"""Initialize the light."""
self._api = api
self._channel = channel
self._status = status
self._effects = effects
self._mac = status['mac']
self._error_reported = False
self._hs_color = [255, 255]
self._brightness = 255
self._effect = None
self._available = True

@property
def unique_id(self) -> str:
"""Return a unique ID."""
return '{}-{}'.format(self._mac, self._channel)

@property
def available(self) -> bool:
"""Return True if entity is available."""
return self._available

@property
def name(self):
"""Return the name of the device."""
return NAME_FORMAT.format(self._mac, self._channel)

@property
def is_on(self):
"""Return true if device is on."""
return self._status['ch{}Active'.format(self._channel)] == 1

@property
def brightness(self):
"""Return the brightness of this light between 0..255."""
return self._brightness

@property
def hs_color(self):
"""Return the color property."""
return self._hs_color

@property
def effect(self):
"""Return the effect property."""
return self._effect

@property
def supported_features(self):
"""Flag supported features."""
return SUPPORT_EVERLIGHTS

@property
def effect_list(self):
"""Return the list of supported effects."""
return self._effects

async def async_turn_on(self, **kwargs):
"""Turn the light on."""
hs_color = kwargs.get(ATTR_HS_COLOR, self._hs_color)
brightness = kwargs.get(ATTR_BRIGHTNESS, self._brightness)
effect = kwargs.get(ATTR_EFFECT)

if effect is not None:
colors = await self._api.set_pattern_by_id(self._channel, effect)

rgb = color_int_to_rgb(colors[0])
hsv = color_util.color_RGB_to_hsv(*rgb)
hs_color = hsv[:2]
brightness = hsv[2] / 100 * 255

else:
rgb = color_util.color_hsv_to_RGB(*hs_color, brightness/255*100)
colors = [color_rgb_to_int(*rgb)]

await self._api.set_pattern(self._channel, colors)

self._hs_color = hs_color
self._brightness = brightness
self._effect = effect

async def async_turn_off(self, **kwargs):
"""Turn the light off."""
await self._api.clear_pattern(self._channel)

async def async_update(self):
"""Synchronize state with control box."""
import pyeverlights

try:
self._status = await self._api.get_status()
except pyeverlights.ConnectionError:
if self._available:
_LOGGER.warning("EverLights control box connection lost.")
self._available = False
else:
if not self._available:
_LOGGER.warning("EverLights control box connection restored.")
self._available = True
3 changes: 3 additions & 0 deletions requirements_all.txt
Original file line number Diff line number Diff line change
Expand Up @@ -981,6 +981,9 @@ pyenvisalink==3.8
# homeassistant.components.climate.ephember
pyephember==0.2.0

# homeassistant.components.light.everlights
pyeverlights==0.1.0

# homeassistant.components.sensor.fido
pyfido==2.1.1

Expand Down
16 changes: 16 additions & 0 deletions tests/components/light/test_everlights.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
"""The tests for the everlights component."""
from homeassistant.components.light import everlights


def test_color_rgb_to_int():
"""Test RGB to integer conversion."""
assert everlights.color_rgb_to_int(0x00, 0x00, 0x00) == 0x000000
assert everlights.color_rgb_to_int(0xff, 0xff, 0xff) == 0xffffff
assert everlights.color_rgb_to_int(0x12, 0x34, 0x56) == 0x123456


def test_int_to_rgb():
"""Test integer to RGB conversion."""
assert everlights.color_int_to_rgb(0x000000) == (0x00, 0x00, 0x00)
assert everlights.color_int_to_rgb(0xffffff) == (0xff, 0xff, 0xff)
assert everlights.color_int_to_rgb(0x123456) == (0x12, 0x34, 0x56)

0 comments on commit 9482a63

Please sign in to comment.