mirror of
https://github.com/home-assistant/core.git
synced 2025-07-19 11:17:21 +00:00
Add transition to LiteJet (#47657)
This commit is contained in:
parent
0f78004ede
commit
72a3860361
@ -10,13 +10,44 @@ import voluptuous as vol
|
|||||||
|
|
||||||
from homeassistant import config_entries
|
from homeassistant import config_entries
|
||||||
from homeassistant.const import CONF_PORT
|
from homeassistant.const import CONF_PORT
|
||||||
|
from homeassistant.core import callback
|
||||||
from homeassistant.data_entry_flow import FlowResult
|
from homeassistant.data_entry_flow import FlowResult
|
||||||
|
import homeassistant.helpers.config_validation as cv
|
||||||
|
|
||||||
from .const import DOMAIN
|
from .const import CONF_DEFAULT_TRANSITION, DOMAIN
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class LiteJetOptionsFlow(config_entries.OptionsFlow):
|
||||||
|
"""Handle LiteJet options."""
|
||||||
|
|
||||||
|
def __init__(self, config_entry):
|
||||||
|
"""Initialize LiteJet options flow."""
|
||||||
|
self.config_entry = config_entry
|
||||||
|
|
||||||
|
async def async_step_init(
|
||||||
|
self, user_input: dict[str, Any] | None = None
|
||||||
|
) -> dict[str, Any]:
|
||||||
|
"""Manage LiteJet options."""
|
||||||
|
if user_input is not None:
|
||||||
|
return self.async_create_entry(title="", data=user_input)
|
||||||
|
|
||||||
|
return self.async_show_form(
|
||||||
|
step_id="init",
|
||||||
|
data_schema=vol.Schema(
|
||||||
|
{
|
||||||
|
vol.Optional(
|
||||||
|
CONF_DEFAULT_TRANSITION,
|
||||||
|
default=self.config_entry.options.get(
|
||||||
|
CONF_DEFAULT_TRANSITION, 0
|
||||||
|
),
|
||||||
|
): cv.positive_int,
|
||||||
|
}
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class LiteJetConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
class LiteJetConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
||||||
"""LiteJet config flow."""
|
"""LiteJet config flow."""
|
||||||
|
|
||||||
@ -54,3 +85,9 @@ class LiteJetConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
|||||||
async def async_step_import(self, import_data):
|
async def async_step_import(self, import_data):
|
||||||
"""Import litejet config from configuration.yaml."""
|
"""Import litejet config from configuration.yaml."""
|
||||||
return self.async_create_entry(title=import_data[CONF_PORT], data=import_data)
|
return self.async_create_entry(title=import_data[CONF_PORT], data=import_data)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
@callback
|
||||||
|
def async_get_options_flow(config_entry):
|
||||||
|
"""Get the options flow for this handler."""
|
||||||
|
return LiteJetOptionsFlow(config_entry)
|
||||||
|
@ -6,3 +6,5 @@ CONF_EXCLUDE_NAMES = "exclude_names"
|
|||||||
CONF_INCLUDE_SWITCHES = "include_switches"
|
CONF_INCLUDE_SWITCHES = "include_switches"
|
||||||
|
|
||||||
PLATFORMS = ["light", "switch", "scene"]
|
PLATFORMS = ["light", "switch", "scene"]
|
||||||
|
|
||||||
|
CONF_DEFAULT_TRANSITION = "default_transition"
|
||||||
|
@ -3,11 +3,13 @@ import logging
|
|||||||
|
|
||||||
from homeassistant.components.light import (
|
from homeassistant.components.light import (
|
||||||
ATTR_BRIGHTNESS,
|
ATTR_BRIGHTNESS,
|
||||||
|
ATTR_TRANSITION,
|
||||||
SUPPORT_BRIGHTNESS,
|
SUPPORT_BRIGHTNESS,
|
||||||
|
SUPPORT_TRANSITION,
|
||||||
LightEntity,
|
LightEntity,
|
||||||
)
|
)
|
||||||
|
|
||||||
from .const import DOMAIN
|
from .const import CONF_DEFAULT_TRANSITION, DOMAIN
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -23,7 +25,7 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
|
|||||||
entities = []
|
entities = []
|
||||||
for i in system.loads():
|
for i in system.loads():
|
||||||
name = system.get_load_name(i)
|
name = system.get_load_name(i)
|
||||||
entities.append(LiteJetLight(config_entry.entry_id, system, i, name))
|
entities.append(LiteJetLight(config_entry, system, i, name))
|
||||||
return entities
|
return entities
|
||||||
|
|
||||||
async_add_entities(await hass.async_add_executor_job(get_entities, system), True)
|
async_add_entities(await hass.async_add_executor_job(get_entities, system), True)
|
||||||
@ -32,9 +34,9 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
|
|||||||
class LiteJetLight(LightEntity):
|
class LiteJetLight(LightEntity):
|
||||||
"""Representation of a single LiteJet light."""
|
"""Representation of a single LiteJet light."""
|
||||||
|
|
||||||
def __init__(self, entry_id, lj, i, name):
|
def __init__(self, config_entry, lj, i, name):
|
||||||
"""Initialize a LiteJet light."""
|
"""Initialize a LiteJet light."""
|
||||||
self._entry_id = entry_id
|
self._config_entry = config_entry
|
||||||
self._lj = lj
|
self._lj = lj
|
||||||
self._index = i
|
self._index = i
|
||||||
self._brightness = 0
|
self._brightness = 0
|
||||||
@ -57,7 +59,7 @@ class LiteJetLight(LightEntity):
|
|||||||
@property
|
@property
|
||||||
def supported_features(self):
|
def supported_features(self):
|
||||||
"""Flag supported features."""
|
"""Flag supported features."""
|
||||||
return SUPPORT_BRIGHTNESS
|
return SUPPORT_BRIGHTNESS | SUPPORT_TRANSITION
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def name(self):
|
def name(self):
|
||||||
@ -67,7 +69,7 @@ class LiteJetLight(LightEntity):
|
|||||||
@property
|
@property
|
||||||
def unique_id(self):
|
def unique_id(self):
|
||||||
"""Return a unique identifier for this light."""
|
"""Return a unique identifier for this light."""
|
||||||
return f"{self._entry_id}_{self._index}"
|
return f"{self._config_entry.entry_id}_{self._index}"
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def brightness(self):
|
def brightness(self):
|
||||||
@ -91,16 +93,33 @@ class LiteJetLight(LightEntity):
|
|||||||
|
|
||||||
def turn_on(self, **kwargs):
|
def turn_on(self, **kwargs):
|
||||||
"""Turn on the light."""
|
"""Turn on the light."""
|
||||||
if ATTR_BRIGHTNESS in kwargs:
|
|
||||||
brightness = int(kwargs[ATTR_BRIGHTNESS] / 255 * 99)
|
# If neither attribute is specified then the simple activate load
|
||||||
self._lj.activate_load_at(self._index, brightness, 0)
|
# LiteJet API will use the per-light default brightness and
|
||||||
else:
|
# transition values programmed in the LiteJet system.
|
||||||
|
if ATTR_BRIGHTNESS not in kwargs and ATTR_TRANSITION not in kwargs:
|
||||||
self._lj.activate_load(self._index)
|
self._lj.activate_load(self._index)
|
||||||
|
return
|
||||||
|
|
||||||
|
# If either attribute is specified then Home Assistant must
|
||||||
|
# control both values.
|
||||||
|
default_transition = self._config_entry.options.get(CONF_DEFAULT_TRANSITION, 0)
|
||||||
|
transition = kwargs.get(ATTR_TRANSITION, default_transition)
|
||||||
|
brightness = int(kwargs.get(ATTR_BRIGHTNESS, 255) / 255 * 99)
|
||||||
|
|
||||||
|
self._lj.activate_load_at(self._index, brightness, int(transition))
|
||||||
|
|
||||||
def turn_off(self, **kwargs):
|
def turn_off(self, **kwargs):
|
||||||
"""Turn off the light."""
|
"""Turn off the light."""
|
||||||
|
if ATTR_TRANSITION in kwargs:
|
||||||
|
self._lj.activate_load_at(self._index, 0, kwargs[ATTR_TRANSITION])
|
||||||
|
return
|
||||||
|
|
||||||
|
# If transition attribute is not specified then the simple
|
||||||
|
# deactivate load LiteJet API will use the per-light default
|
||||||
|
# transition value programmed in the LiteJet system.
|
||||||
self._lj.deactivate_load(self._index)
|
self._lj.deactivate_load(self._index)
|
||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
"""Retrieve the light's brightness from the LiteJet system."""
|
"""Retrieve the light's brightness from the LiteJet system."""
|
||||||
self._brightness = self._lj.get_load_level(self._index) / 99 * 255
|
self._brightness = int(self._lj.get_load_level(self._index) / 99 * 255)
|
||||||
|
@ -15,5 +15,15 @@
|
|||||||
"error": {
|
"error": {
|
||||||
"open_failed": "Cannot open the specified serial port."
|
"open_failed": "Cannot open the specified serial port."
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"options": {
|
||||||
|
"step": {
|
||||||
|
"init": {
|
||||||
|
"title": "Configure LiteJet",
|
||||||
|
"data": {
|
||||||
|
"default_transition": "Default Transition (seconds)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -15,5 +15,15 @@
|
|||||||
"title": "Connect To LiteJet"
|
"title": "Connect To LiteJet"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"options": {
|
||||||
|
"step": {
|
||||||
|
"init": {
|
||||||
|
"data": {
|
||||||
|
"default_transition": "Default Transition (seconds)"
|
||||||
|
},
|
||||||
|
"title": "Configure LiteJet"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -3,8 +3,8 @@ from unittest.mock import patch
|
|||||||
|
|
||||||
from serial import SerialException
|
from serial import SerialException
|
||||||
|
|
||||||
from homeassistant import config_entries
|
from homeassistant import config_entries, data_entry_flow
|
||||||
from homeassistant.components.litejet.const import DOMAIN
|
from homeassistant.components.litejet.const import CONF_DEFAULT_TRANSITION, DOMAIN
|
||||||
from homeassistant.const import CONF_PORT
|
from homeassistant.const import CONF_PORT
|
||||||
|
|
||||||
from tests.common import MockConfigEntry
|
from tests.common import MockConfigEntry
|
||||||
@ -76,3 +76,22 @@ async def test_import_step(hass):
|
|||||||
assert result["type"] == "create_entry"
|
assert result["type"] == "create_entry"
|
||||||
assert result["title"] == test_data[CONF_PORT]
|
assert result["title"] == test_data[CONF_PORT]
|
||||||
assert result["data"] == test_data
|
assert result["data"] == test_data
|
||||||
|
|
||||||
|
|
||||||
|
async def test_options(hass):
|
||||||
|
"""Test updating options."""
|
||||||
|
entry = MockConfigEntry(domain=DOMAIN, data={CONF_PORT: "/dev/test"})
|
||||||
|
entry.add_to_hass(hass)
|
||||||
|
|
||||||
|
result = await hass.config_entries.options.async_init(entry.entry_id)
|
||||||
|
|
||||||
|
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
|
||||||
|
assert result["step_id"] == "init"
|
||||||
|
|
||||||
|
result = await hass.config_entries.options.async_configure(
|
||||||
|
result["flow_id"],
|
||||||
|
user_input={CONF_DEFAULT_TRANSITION: 12},
|
||||||
|
)
|
||||||
|
|
||||||
|
assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
|
||||||
|
assert result["data"] == {CONF_DEFAULT_TRANSITION: 12}
|
||||||
|
@ -2,7 +2,8 @@
|
|||||||
import logging
|
import logging
|
||||||
|
|
||||||
from homeassistant.components import light
|
from homeassistant.components import light
|
||||||
from homeassistant.components.light import ATTR_BRIGHTNESS
|
from homeassistant.components.light import ATTR_BRIGHTNESS, ATTR_TRANSITION
|
||||||
|
from homeassistant.components.litejet.const import CONF_DEFAULT_TRANSITION
|
||||||
from homeassistant.const import ATTR_ENTITY_ID, SERVICE_TURN_OFF, SERVICE_TURN_ON
|
from homeassistant.const import ATTR_ENTITY_ID, SERVICE_TURN_OFF, SERVICE_TURN_ON
|
||||||
|
|
||||||
from . import async_init_integration
|
from . import async_init_integration
|
||||||
@ -33,6 +34,55 @@ async def test_on_brightness(hass, mock_litejet):
|
|||||||
mock_litejet.activate_load_at.assert_called_with(ENTITY_LIGHT_NUMBER, 39, 0)
|
mock_litejet.activate_load_at.assert_called_with(ENTITY_LIGHT_NUMBER, 39, 0)
|
||||||
|
|
||||||
|
|
||||||
|
async def test_default_transition(hass, mock_litejet):
|
||||||
|
"""Test turning the light on with the default transition option."""
|
||||||
|
entry = await async_init_integration(hass)
|
||||||
|
|
||||||
|
hass.config_entries.async_update_entry(entry, options={CONF_DEFAULT_TRANSITION: 12})
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
assert hass.states.get(ENTITY_LIGHT).state == "off"
|
||||||
|
assert hass.states.get(ENTITY_OTHER_LIGHT).state == "off"
|
||||||
|
|
||||||
|
assert not light.is_on(hass, ENTITY_LIGHT)
|
||||||
|
|
||||||
|
await hass.services.async_call(
|
||||||
|
light.DOMAIN,
|
||||||
|
SERVICE_TURN_ON,
|
||||||
|
{ATTR_ENTITY_ID: ENTITY_LIGHT, ATTR_BRIGHTNESS: 102},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
mock_litejet.activate_load_at.assert_called_with(ENTITY_LIGHT_NUMBER, 39, 12)
|
||||||
|
|
||||||
|
|
||||||
|
async def test_transition(hass, mock_litejet):
|
||||||
|
"""Test turning the light on with transition."""
|
||||||
|
await async_init_integration(hass)
|
||||||
|
|
||||||
|
assert hass.states.get(ENTITY_LIGHT).state == "off"
|
||||||
|
assert hass.states.get(ENTITY_OTHER_LIGHT).state == "off"
|
||||||
|
|
||||||
|
assert not light.is_on(hass, ENTITY_LIGHT)
|
||||||
|
|
||||||
|
# On
|
||||||
|
await hass.services.async_call(
|
||||||
|
light.DOMAIN,
|
||||||
|
SERVICE_TURN_ON,
|
||||||
|
{ATTR_ENTITY_ID: ENTITY_LIGHT, ATTR_TRANSITION: 5},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
mock_litejet.activate_load_at.assert_called_with(ENTITY_LIGHT_NUMBER, 99, 5)
|
||||||
|
|
||||||
|
# Off
|
||||||
|
await hass.services.async_call(
|
||||||
|
light.DOMAIN,
|
||||||
|
SERVICE_TURN_OFF,
|
||||||
|
{ATTR_ENTITY_ID: ENTITY_LIGHT, ATTR_TRANSITION: 5},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
mock_litejet.activate_load_at.assert_called_with(ENTITY_LIGHT_NUMBER, 0, 5)
|
||||||
|
|
||||||
|
|
||||||
async def test_on_off(hass, mock_litejet):
|
async def test_on_off(hass, mock_litejet):
|
||||||
"""Test turning the light on and off."""
|
"""Test turning the light on and off."""
|
||||||
await async_init_integration(hass)
|
await async_init_integration(hass)
|
||||||
@ -91,9 +141,7 @@ async def test_activated_event(hass, mock_litejet):
|
|||||||
assert light.is_on(hass, ENTITY_OTHER_LIGHT)
|
assert light.is_on(hass, ENTITY_OTHER_LIGHT)
|
||||||
assert hass.states.get(ENTITY_LIGHT).state == "on"
|
assert hass.states.get(ENTITY_LIGHT).state == "on"
|
||||||
assert hass.states.get(ENTITY_OTHER_LIGHT).state == "on"
|
assert hass.states.get(ENTITY_OTHER_LIGHT).state == "on"
|
||||||
assert (
|
assert hass.states.get(ENTITY_OTHER_LIGHT).attributes.get(ATTR_BRIGHTNESS) == 103
|
||||||
int(hass.states.get(ENTITY_OTHER_LIGHT).attributes.get(ATTR_BRIGHTNESS)) == 103
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
async def test_deactivated_event(hass, mock_litejet):
|
async def test_deactivated_event(hass, mock_litejet):
|
||||||
|
Loading…
x
Reference in New Issue
Block a user