Skip to content

Commit

Permalink
Add GUI config support
Browse files Browse the repository at this point in the history
  • Loading branch information
AlexxIT committed Dec 8, 2020
1 parent f732193 commit c50f5ca
Show file tree
Hide file tree
Showing 6 changed files with 209 additions and 19 deletions.
35 changes: 35 additions & 0 deletions custom_components/gyverlamp/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant

DOMAIN = 'gyverlamp'


async def async_setup(hass, hass_config):
# used only with GUI setup
hass.data[DOMAIN] = {}
return True


async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry):
# migrate data (after first setup) to options
if entry.data:
hass.config_entries.async_update_entry(entry, data={},
options=entry.data)

# add options handler
entry.add_update_listener(async_update_options)

# forward to light setup
coro = hass.config_entries.async_forward_entry_setup(entry, 'light')
hass.async_create_task(coro)

return True


async def async_update_options(hass: HomeAssistant, entry: ConfigEntry):
# update entity config
hass.data[DOMAIN][entry.entry_id].update_config(entry.options)


async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry):
return await hass.config_entries.async_forward_entry_unload(entry, 'light')
58 changes: 58 additions & 0 deletions custom_components/gyverlamp/config_flow.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import re

import homeassistant.helpers.config_validation as cv
import voluptuous as vol
from homeassistant.config_entries import ConfigFlow, OptionsFlow, ConfigEntry
from homeassistant.const import CONF_HOST
from homeassistant.core import callback

from . import DOMAIN
from .light import CONF_EFFECTS, EFFECTS


def parse_effects(data: str) -> list:
return re.split(r'\s*,\s*', data.strip())


class ConfigFlowHandler(ConfigFlow, domain=DOMAIN):
VERSION = 1

async def async_step_user(self, user_input=None):
if user_input is not None:
host = user_input[CONF_HOST]
user_input[CONF_EFFECTS] = parse_effects(user_input[CONF_EFFECTS])
return self.async_create_entry(title=host, data=user_input)

effects = ','.join(EFFECTS)
return self.async_show_form(
step_id='user',
data_schema=vol.Schema({
vol.Required(CONF_HOST): cv.string,
vol.Optional(CONF_EFFECTS, default=effects): cv.string
})
)

@staticmethod
@callback
def async_get_options_flow(config_entry):
return OptionsFlowHandler(config_entry)


class OptionsFlowHandler(OptionsFlow):
def __init__(self, config_entry: ConfigEntry):
self.config_entry = config_entry

async def async_step_init(self, user_input=None):
host = self.config_entry.options[CONF_HOST]
effects = ','.join(self.config_entry.options[CONF_EFFECTS])
return self.async_show_form(
step_id='user',
data_schema=vol.Schema({
vol.Required(CONF_HOST, default=host): cv.string,
vol.Optional(CONF_EFFECTS, default=effects): cv.string
})
)

async def async_step_user(self, user_input: dict = None):
user_input[CONF_EFFECTS] = parse_effects(user_input[CONF_EFFECTS])
return self.async_create_entry(title='', data=user_input)
88 changes: 70 additions & 18 deletions custom_components/gyverlamp/light.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,42 +6,70 @@
from homeassistant.components.light import PLATFORM_SCHEMA, LightEntity, \
SUPPORT_BRIGHTNESS, SUPPORT_EFFECT, SUPPORT_COLOR, ATTR_BRIGHTNESS, \
ATTR_EFFECT, ATTR_HS_COLOR
from homeassistant.const import CONF_HOST
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_HOST, CONF_NAME
from homeassistant.core import HomeAssistant

from . import DOMAIN

_LOGGER = logging.getLogger(__name__)

PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Required(CONF_HOST): cv.string
})
CONF_EFFECTS = 'effects'

EFFECTS = ["Конфетти", "Огонь", "Радуга вертикальная", "Радуга горизонтальная",
"Смена цвета", "Безумие", "Облака", "Лава", "Плазма", "Радуга",
"Павлин", "Зебра", "Лес", "Океан", "Цвет", "Снег", "Матрица",
"Светлячки"]
FEATURES = SUPPORT_BRIGHTNESS | SUPPORT_EFFECT | SUPPORT_COLOR

PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Required(CONF_HOST): cv.string,
vol.Optional(CONF_NAME): cv.string,
vol.Optional(CONF_EFFECTS): cv.ensure_list
})


def setup_platform(hass, config, add_entities, discovery_info=None):
host = config[CONF_HOST]
add_entities([GyverLamp(host)])
add_entities([GyverLamp(config)], True)


async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry,
async_add_entities):
entity = GyverLamp(entry.options, entry.entry_id)
async_add_entities([entity], True)

hass.data[DOMAIN][entry.entry_id] = entity


async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry):
hass.data[DOMAIN].pop(entry.entry_id)
return True


class GyverLamp(LightEntity):
def __init__(self, host: str, port: int = 8888):
self.address = (host, port)
_brightness = None
_effect = None
_effects = None
_host = None
_hs_color = None
_is_on = None

def __init__(self, config: dict, unique_id=None):
self._name = config.get(CONF_NAME, "Gyver Lamp")
self._unique_id = unique_id

self._effect = None
self._brightness = None
self._hs_color = None
self._is_on = None
self.update_config(config)

@property
def should_poll(self):
return True

@property
def unique_id(self):
return self._unique_id

@property
def name(self):
return "Gyver Lamp"
return self._name

@property
def brightness(self):
Expand All @@ -53,20 +81,42 @@ def hs_color(self):

@property
def effect_list(self):
return EFFECTS
return self._effects

@property
def effect(self):
return self._effect

@property
def supported_features(self):
return FEATURES
return SUPPORT_BRIGHTNESS | SUPPORT_EFFECT | SUPPORT_COLOR

@property
def is_on(self):
return self._is_on

@property
def device_info(self):
"""
https://developers.home-assistant.io/docs/device_registry_index/
"""
return {
'identifiers': {(DOMAIN, self._unique_id)},
'manufacturer': "@AlexGyver",
'model': "GyverLamp"
}

@property
def address(self) -> tuple:
return self._host, 8888

def update_config(self, config: dict):
self._effects = config.get(CONF_EFFECTS, EFFECTS)
self._host = config[CONF_HOST]

if self.hass:
self._async_write_ha_state()

def turn_on(self, **kwargs):
self.update()

Expand All @@ -75,7 +125,8 @@ def turn_on(self, **kwargs):
payload.append('BRI%d' % kwargs[ATTR_BRIGHTNESS])

if ATTR_EFFECT in kwargs:
payload.append('EFF%d' % EFFECTS.index(kwargs[ATTR_EFFECT]))
effect = kwargs[ATTR_EFFECT]
payload.append('EFF%d' % self._effects.index(effect))

if ATTR_HS_COLOR in kwargs:
scale = round(kwargs[ATTR_HS_COLOR][0] / 360.0 * 100.0)
Expand Down Expand Up @@ -108,7 +159,8 @@ def update(self):
data = sock.recv(1024).decode().split(' ')
_LOGGER.debug("UPDATE %s", data)
# bri eff spd sca pow
self._effect = EFFECTS[int(data[1])]
i = int(data[1])
self._effect = self._effects[i] if i < len(self._effects) else None
self._brightness = int(data[2])
self._hs_color = (float(data[4]) / 100.0 * 360.0,
float(data[3]) / 255.0 * 100.0)
Expand Down
3 changes: 2 additions & 1 deletion custom_components/gyverlamp/manifest.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"domain": "GyverLamp",
"domain": "gyverlamp",
"name": "GyverLamp",
"config_flow": true,
"documentation": "https://github.com/AlexxIT/GyverLamp",
"dependencies": [],
"codeowners": [
Expand Down
22 changes: 22 additions & 0 deletions custom_components/gyverlamp/translations/en.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"config": {
"step": {
"user": {
"data": {
"host": "Host",
"effects": "Effects"
}
}
}
},
"options": {
"step": {
"user": {
"data": {
"host": "Host",
"effects": "Effects"
}
}
}
}
}
22 changes: 22 additions & 0 deletions custom_components/gyverlamp/translations/ru.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"config": {
"step": {
"user": {
"data": {
"host": "Хост",
"effects": "Эффекты"
}
}
}
},
"options": {
"step": {
"user": {
"data": {
"host": "Хост",
"effects": "Эффекты"
}
}
}
}
}

0 comments on commit c50f5ca

Please sign in to comment.