From cdbf2f9293bbaaa1fdff24aece194a52f215b3da Mon Sep 17 00:00:00 2001 From: starkillerOG Date: Sat, 13 Jan 2018 21:06:34 +0100 Subject: [PATCH] Hyperion: Add brightness, HDMI and effect support (#11543) * Hyperion: Add brightness, HDMI and effect support - added brightness support to dim the hyperion light - changed the "OFF" command to set the color to [0,0,0] after clearing all priorities. This is neccesary to keep the light turned off when an HDMI grabber is used for ambilight with hyperion. - added HDMI ambilight mode recognition and control. by setting the "hdmi_priority" in your "configuration.yaml" file (defaults to 880), home assistant will now be able to recognize when the hyperion light is in HDMI ambilight mode and will change its icon to an HDMI symbol and set the status to ON. Switching the hyperion light to HDMI ambilight mode can be done through the effect option (clears all priorities such that the HDMI grabber remains). - added effect support for the default effects of hyperion, a custom list can be defined in the "configuration.yaml" file by using the "effect_list" option. * Hyperion: Add brightness, HDMI and effect support - added brightness support to dim the hyperion light - changed the "OFF" command to set the color to [0,0,0] after clearing all priorities. This is neccesary to keep the light turned off when an HDMI grabber is used for ambilight with hyperion. - added HDMI ambilight mode recognition and control. by setting the "hdmi_priority" in your "configuration.yaml" file (defaults to 880), home assistant will now be able to recognize when the hyperion light is in HDMI ambilight mode and will change its icon to an HDMI symbol and set the status to ON. Switching the hyperion light to HDMI ambilight mode can be done through the effect option (clears all priorities such that the HDMI grabber remains). - added effect support for the default effects of hyperion, a custom list can be defined in the "configuration.yaml" file by using the "effect_list" option. - fixed some style issues with too long lines * Hyperion: Add brightness, HDMI and effect support - fixed some more indentation style issues * Hyperion: Add brightness, HDMI and effect support - yet more fixed visuel indent issues * Hyperion: Add brightness, HDMI and effect support - more visuel indents * Hyperion: Add brightness, HDMI and effect support - fixed invalid variable "A" * Hyperion: Add brightness, HDMI and effect support - remove unnececary brackets - specify specific exceptions * correct changing state holding attributes during a service method Proccesed the comments of @MartinHjelmare: https://github.com/home-assistant/home-assistant/pull/11543#pullrequestreview-88328659 * indent correction corrected tab instead of 4 spaces * Hyperion: Add brightness, HDMI and effect support - changed 'none' to None - renamed "self._skip_check" to "self._skip_update" * Add brightness, HDMI and effect support changed checking if a list is empty from "list == []" to "not list" --- homeassistant/components/light/hyperion.py | 141 +++++++++++++++++++-- 1 file changed, 130 insertions(+), 11 deletions(-) diff --git a/homeassistant/components/light/hyperion.py b/homeassistant/components/light/hyperion.py index 88bdc1a4c95..644c1e84ebe 100644 --- a/homeassistant/components/light/hyperion.py +++ b/homeassistant/components/light/hyperion.py @@ -11,7 +11,8 @@ import socket import voluptuous as vol from homeassistant.components.light import ( - ATTR_RGB_COLOR, SUPPORT_RGB_COLOR, Light, PLATFORM_SCHEMA) + ATTR_BRIGHTNESS, ATTR_RGB_COLOR, ATTR_EFFECT, SUPPORT_BRIGHTNESS, + SUPPORT_RGB_COLOR, SUPPORT_EFFECT, Light, PLATFORM_SCHEMA) from homeassistant.const import (CONF_HOST, CONF_PORT, CONF_NAME) import homeassistant.helpers.config_validation as cv @@ -19,13 +20,27 @@ _LOGGER = logging.getLogger(__name__) CONF_DEFAULT_COLOR = 'default_color' CONF_PRIORITY = 'priority' +CONF_HDMI_PRIORITY = 'hdmi_priority' +CONF_EFFECT_LIST = 'effect_list' DEFAULT_COLOR = [255, 255, 255] DEFAULT_NAME = 'Hyperion' DEFAULT_PORT = 19444 DEFAULT_PRIORITY = 128 +DEFAULT_HDMI_PRIORITY = 880 +DEFAULT_EFFECT_LIST = ['HDMI', 'Cinema brighten lights', 'Cinema dim lights', + 'Knight rider', 'Blue mood blobs', 'Cold mood blobs', + 'Full color mood blobs', 'Green mood blobs', + 'Red mood blobs', 'Warm mood blobs', + 'Police Lights Single', 'Police Lights Solid', + 'Rainbow mood', 'Rainbow swirl fast', + 'Rainbow swirl', 'Random', 'Running dots', + 'System Shutdown', 'Snake', 'Sparks Color', 'Sparks', + 'Strobe blue', 'Strobe Raspbmc', 'Strobe white', + 'Color traces', 'UDP multicast listener', + 'UDP listener', 'X-Mas'] -SUPPORT_HYPERION = SUPPORT_RGB_COLOR +SUPPORT_HYPERION = (SUPPORT_RGB_COLOR | SUPPORT_BRIGHTNESS | SUPPORT_EFFECT) PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ vol.Required(CONF_HOST): cv.string, @@ -35,6 +50,11 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ [vol.All(vol.Coerce(int), vol.Range(min=0, max=255))]), vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, vol.Optional(CONF_PRIORITY, default=DEFAULT_PRIORITY): cv.positive_int, + vol.Optional(CONF_HDMI_PRIORITY, + default=DEFAULT_HDMI_PRIORITY): cv.positive_int, + vol.Optional(CONF_EFFECT_LIST, + default=DEFAULT_EFFECT_LIST): vol.All(cv.ensure_list, + [cv.string]), }) @@ -43,10 +63,12 @@ def setup_platform(hass, config, add_devices, discovery_info=None): host = config.get(CONF_HOST) port = config.get(CONF_PORT) priority = config.get(CONF_PRIORITY) + hdmi_priority = config.get(CONF_HDMI_PRIORITY) default_color = config.get(CONF_DEFAULT_COLOR) + effect_list = config.get(CONF_EFFECT_LIST) device = Hyperion(config.get(CONF_NAME), host, port, priority, - default_color) + default_color, hdmi_priority, effect_list) if device.setup(): add_devices([device]) @@ -57,20 +79,33 @@ def setup_platform(hass, config, add_devices, discovery_info=None): class Hyperion(Light): """Representation of a Hyperion remote.""" - def __init__(self, name, host, port, priority, default_color): + def __init__(self, name, host, port, priority, default_color, + hdmi_priority, effect_list): """Initialize the light.""" self._host = host self._port = port self._name = name self._priority = priority + self._hdmi_priority = hdmi_priority self._default_color = default_color self._rgb_color = [0, 0, 0] + self._rgb_mem = [0, 0, 0] + self._brightness = 255 + self._icon = 'mdi:lightbulb' + self._effect_list = effect_list + self._effect = None + self._skip_update = False @property def name(self): """Return the name of the light.""" return self._name + @property + def brightness(self): + """Return the brightness of this light between 0..255.""" + return self._brightness + @property def rgb_color(self): """Return last RGB color value set.""" @@ -81,6 +116,21 @@ class Hyperion(Light): """Return true if not black.""" return self._rgb_color != [0, 0, 0] + @property + def icon(self): + """Return state specific icon.""" + return self._icon + + @property + def effect(self): + """Return the current effect.""" + return self._effect + + @property + def effect_list(self): + """Return the list of supported effects.""" + return self._effect_list + @property def supported_features(self): """Flag supported features.""" @@ -89,35 +139,104 @@ class Hyperion(Light): def turn_on(self, **kwargs): """Turn the lights on.""" if ATTR_RGB_COLOR in kwargs: - self._rgb_color = kwargs[ATTR_RGB_COLOR] + rgb_color = kwargs[ATTR_RGB_COLOR] + elif self._rgb_mem == [0, 0, 0]: + rgb_color = self._default_color else: - self._rgb_color = self._default_color + rgb_color = self._rgb_mem + if ATTR_BRIGHTNESS in kwargs: + brightness = kwargs[ATTR_BRIGHTNESS] + + if ATTR_EFFECT in kwargs: + self._skip_update = True + self._effect = kwargs[ATTR_EFFECT] + if self._effect == 'HDMI': + self.json_request({'command': 'clearall'}) + self._icon = 'mdi:video-input-hdmi' + self._brightness = 255 + self._rgb_color = [125, 125, 125] + else: + self.json_request({ + 'command': 'effect', + 'priority': self._priority, + 'effect': {'name': self._effect} + }) + self._icon = 'mdi:lava-lamp' + self._rgb_color = [175, 0, 255] + return + + cal_color = [int(round(x*float(brightness)/255)) + for x in rgb_color] self.json_request({ 'command': 'color', 'priority': self._priority, - 'color': self._rgb_color + 'color': cal_color }) def turn_off(self, **kwargs): """Disconnect all remotes.""" self.json_request({'command': 'clearall'}) - self._rgb_color = [0, 0, 0] + self.json_request({ + 'command': 'color', + 'priority': self._priority, + 'color': [0, 0, 0] + }) def update(self): - """Get the remote's active color.""" + """Get the lights status.""" + # postpone the immediate state check for changes that take time + if self._skip_update: + self._skip_update = False + return response = self.json_request({'command': 'serverinfo'}) if response: # workaround for outdated Hyperion if 'activeLedColor' not in response['info']: self._rgb_color = self._default_color + self._rgb_mem = self._default_color + self._brightness = 255 + self._icon = 'mdi:lightbulb' + self._effect = None return + # Check if Hyperion is in ambilight mode trough an HDMI grabber + try: + active_priority = response['info']['priorities'][0]['priority'] + if active_priority == self._hdmi_priority: + self._brightness = 255 + self._rgb_color = [125, 125, 125] + self._icon = 'mdi:video-input-hdmi' + self._effect = 'HDMI' + return + except (KeyError, IndexError): + pass - if response['info']['activeLedColor'] == []: - self._rgb_color = [0, 0, 0] + if not response['info']['activeLedColor']: + # Get the active effect + if response['info']['activeEffects']: + self._rgb_color = [175, 0, 255] + self._icon = 'mdi:lava-lamp' + try: + s_name = response['info']['activeEffects'][0]["script"] + s_name = s_name.split('/')[-1][:-3].split("-")[0] + self._effect = [x for x in self._effect_list + if s_name.lower() in x.lower()][0] + except (KeyError, IndexError): + self._effect = None + # Bulb off state + else: + self._rgb_color = [0, 0, 0] + self._icon = 'mdi:lightbulb' + self._effect = None else: + # Get the RGB color self._rgb_color =\ response['info']['activeLedColor'][0]['RGB Value'] + self._brightness = max(self._rgb_color) + self._rgb_mem = [int(round(float(x)*255/self._brightness)) + for x in self._rgb_color] + self._icon = 'mdi:lightbulb' + self._effect = None def setup(self): """Get the hostname of the remote."""