Flux led config flow (#56354)
Co-authored-by: Milan Meulemans <milan.meulemans@live.be> Co-authored-by: Erik Montnemery <erik@montnemery.com> Co-authored-by: J. Nick Koston <nick@koston.org>
This commit is contained in:
parent
80c97a2416
commit
a95c6b10f7
20 changed files with 2142 additions and 201 deletions
1
tests/components/flux_led/__init.py__
Normal file
1
tests/components/flux_led/__init.py__
Normal file
|
@ -0,0 +1 @@
|
|||
"""Tests for the flux_led integration."""
|
57
tests/components/flux_led/__init__.py
Normal file
57
tests/components/flux_led/__init__.py
Normal file
|
@ -0,0 +1,57 @@
|
|||
"""Tests for the flux_led integration."""
|
||||
from __future__ import annotations
|
||||
|
||||
import socket
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
from flux_led import WifiLedBulb
|
||||
|
||||
from homeassistant.components.dhcp import (
|
||||
HOSTNAME as DHCP_HOSTNAME,
|
||||
IP_ADDRESS as DHCP_IP_ADDRESS,
|
||||
MAC_ADDRESS as DHCP_MAC_ADDRESS,
|
||||
)
|
||||
from homeassistant.components.flux_led.const import FLUX_HOST, FLUX_MAC, FLUX_MODEL
|
||||
|
||||
MODULE = "homeassistant.components.flux_led"
|
||||
MODULE_CONFIG_FLOW = "homeassistant.components.flux_led.config_flow"
|
||||
IP_ADDRESS = "127.0.0.1"
|
||||
MODEL = "AZ120444"
|
||||
MAC_ADDRESS = "aa:bb:cc:dd:ee:ff"
|
||||
FLUX_MAC_ADDRESS = "aabbccddeeff"
|
||||
|
||||
DEFAULT_ENTRY_TITLE = f"{MODEL} {FLUX_MAC_ADDRESS}"
|
||||
|
||||
DHCP_DISCOVERY = {
|
||||
DHCP_HOSTNAME: MODEL,
|
||||
DHCP_IP_ADDRESS: IP_ADDRESS,
|
||||
DHCP_MAC_ADDRESS: MAC_ADDRESS,
|
||||
}
|
||||
FLUX_DISCOVERY = {FLUX_HOST: IP_ADDRESS, FLUX_MODEL: MODEL, FLUX_MAC: FLUX_MAC_ADDRESS}
|
||||
|
||||
|
||||
def _mocked_bulb() -> WifiLedBulb:
|
||||
bulb = MagicMock(auto_spec=WifiLedBulb)
|
||||
bulb.getRgb = MagicMock(return_value=[255, 0, 0])
|
||||
bulb.getRgbw = MagicMock(return_value=[255, 0, 0, 50])
|
||||
bulb.brightness = 128
|
||||
bulb.rgbwcapable = True
|
||||
return bulb
|
||||
|
||||
|
||||
def _patch_discovery(device=None, no_device=False):
|
||||
def _discovery(*args, **kwargs):
|
||||
if no_device:
|
||||
return []
|
||||
return [FLUX_DISCOVERY]
|
||||
|
||||
return patch("homeassistant.components.flux_led.BulbScanner.scan", new=_discovery)
|
||||
|
||||
|
||||
def _patch_wifibulb(device=None, no_device=False):
|
||||
def _wifi_led_bulb(*args, **kwargs):
|
||||
if no_device:
|
||||
raise socket.timeout
|
||||
return device if device else _mocked_bulb()
|
||||
|
||||
return patch("homeassistant.components.flux_led.WifiLedBulb", new=_wifi_led_bulb)
|
456
tests/components/flux_led/test_config_flow.py
Normal file
456
tests/components/flux_led/test_config_flow.py
Normal file
|
@ -0,0 +1,456 @@
|
|||
"""Define tests for the Flux LED/Magic Home config flow."""
|
||||
from __future__ import annotations
|
||||
|
||||
from unittest.mock import patch
|
||||
|
||||
import pytest
|
||||
|
||||
from homeassistant import config_entries, setup
|
||||
from homeassistant.components.flux_led.const import (
|
||||
CONF_CUSTOM_EFFECT_COLORS,
|
||||
CONF_CUSTOM_EFFECT_SPEED_PCT,
|
||||
CONF_CUSTOM_EFFECT_TRANSITION,
|
||||
DOMAIN,
|
||||
MODE_AUTO,
|
||||
MODE_RGB,
|
||||
TRANSITION_JUMP,
|
||||
TRANSITION_STROBE,
|
||||
)
|
||||
from homeassistant.const import (
|
||||
CONF_DEVICE,
|
||||
CONF_HOST,
|
||||
CONF_MAC,
|
||||
CONF_MODE,
|
||||
CONF_NAME,
|
||||
CONF_PROTOCOL,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.data_entry_flow import RESULT_TYPE_ABORT, RESULT_TYPE_FORM
|
||||
|
||||
from . import (
|
||||
DEFAULT_ENTRY_TITLE,
|
||||
DHCP_DISCOVERY,
|
||||
DHCP_HOSTNAME,
|
||||
DHCP_IP_ADDRESS,
|
||||
DHCP_MAC_ADDRESS,
|
||||
FLUX_DISCOVERY,
|
||||
IP_ADDRESS,
|
||||
MAC_ADDRESS,
|
||||
MODULE,
|
||||
_patch_discovery,
|
||||
_patch_wifibulb,
|
||||
)
|
||||
|
||||
from tests.common import MockConfigEntry
|
||||
|
||||
|
||||
async def test_discovery(hass: HomeAssistant):
|
||||
"""Test setting up discovery."""
|
||||
with _patch_discovery(), _patch_wifibulb():
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
assert result["type"] == "form"
|
||||
assert result["step_id"] == "user"
|
||||
assert not result["errors"]
|
||||
|
||||
result2 = await hass.config_entries.flow.async_configure(result["flow_id"], {})
|
||||
await hass.async_block_till_done()
|
||||
assert result2["type"] == "form"
|
||||
assert result2["step_id"] == "pick_device"
|
||||
assert not result2["errors"]
|
||||
|
||||
# test we can try again
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
||||
)
|
||||
assert result["type"] == "form"
|
||||
assert result["step_id"] == "user"
|
||||
assert not result["errors"]
|
||||
|
||||
result2 = await hass.config_entries.flow.async_configure(result["flow_id"], {})
|
||||
await hass.async_block_till_done()
|
||||
assert result2["type"] == "form"
|
||||
assert result2["step_id"] == "pick_device"
|
||||
assert not result2["errors"]
|
||||
|
||||
with _patch_discovery(), _patch_wifibulb(), patch(
|
||||
f"{MODULE}.async_setup", return_value=True
|
||||
) as mock_setup, patch(
|
||||
f"{MODULE}.async_setup_entry", return_value=True
|
||||
) as mock_setup_entry:
|
||||
result3 = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"],
|
||||
{CONF_DEVICE: MAC_ADDRESS},
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert result3["type"] == "create_entry"
|
||||
assert result3["title"] == DEFAULT_ENTRY_TITLE
|
||||
assert result3["data"] == {CONF_HOST: IP_ADDRESS, CONF_NAME: DEFAULT_ENTRY_TITLE}
|
||||
mock_setup.assert_called_once()
|
||||
mock_setup_entry.assert_called_once()
|
||||
|
||||
# ignore configured devices
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
||||
)
|
||||
assert result["type"] == "form"
|
||||
assert result["step_id"] == "user"
|
||||
assert not result["errors"]
|
||||
|
||||
with _patch_discovery(), _patch_wifibulb():
|
||||
result2 = await hass.config_entries.flow.async_configure(result["flow_id"], {})
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert result2["type"] == "abort"
|
||||
assert result2["reason"] == "no_devices_found"
|
||||
|
||||
|
||||
async def test_discovery_with_existing_device_present(hass: HomeAssistant):
|
||||
"""Test setting up discovery."""
|
||||
config_entry = MockConfigEntry(
|
||||
domain=DOMAIN, data={CONF_HOST: "127.0.0.2"}, unique_id="dd:dd:dd:dd:dd:dd"
|
||||
)
|
||||
config_entry.add_to_hass(hass)
|
||||
|
||||
with _patch_discovery(), _patch_wifibulb(no_device=True):
|
||||
await hass.config_entries.async_setup(config_entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
||||
)
|
||||
assert result["type"] == "form"
|
||||
assert result["step_id"] == "user"
|
||||
assert not result["errors"]
|
||||
|
||||
with _patch_discovery(), _patch_wifibulb():
|
||||
result2 = await hass.config_entries.flow.async_configure(result["flow_id"], {})
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert result2["type"] == "form"
|
||||
assert result2["step_id"] == "pick_device"
|
||||
assert not result2["errors"]
|
||||
|
||||
# Now abort and make sure we can start over
|
||||
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
||||
)
|
||||
assert result["type"] == "form"
|
||||
assert result["step_id"] == "user"
|
||||
assert not result["errors"]
|
||||
|
||||
with _patch_discovery(), _patch_wifibulb():
|
||||
result2 = await hass.config_entries.flow.async_configure(result["flow_id"], {})
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert result2["type"] == "form"
|
||||
assert result2["step_id"] == "pick_device"
|
||||
assert not result2["errors"]
|
||||
|
||||
with _patch_discovery(), _patch_wifibulb(), patch(
|
||||
f"{MODULE}.async_setup_entry", return_value=True
|
||||
) as mock_setup_entry:
|
||||
result3 = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"], {CONF_DEVICE: MAC_ADDRESS}
|
||||
)
|
||||
assert result3["type"] == "create_entry"
|
||||
assert result3["title"] == DEFAULT_ENTRY_TITLE
|
||||
assert result3["data"] == {
|
||||
CONF_HOST: IP_ADDRESS,
|
||||
CONF_NAME: DEFAULT_ENTRY_TITLE,
|
||||
}
|
||||
await hass.async_block_till_done()
|
||||
|
||||
mock_setup_entry.assert_called_once()
|
||||
|
||||
# ignore configured devices
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
||||
)
|
||||
assert result["type"] == "form"
|
||||
assert result["step_id"] == "user"
|
||||
assert not result["errors"]
|
||||
|
||||
with _patch_discovery(), _patch_wifibulb():
|
||||
result2 = await hass.config_entries.flow.async_configure(result["flow_id"], {})
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert result2["type"] == "abort"
|
||||
assert result2["reason"] == "no_devices_found"
|
||||
|
||||
|
||||
async def test_discovery_no_device(hass: HomeAssistant):
|
||||
"""Test discovery without device."""
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
||||
)
|
||||
|
||||
with _patch_discovery(no_device=True), _patch_wifibulb():
|
||||
result2 = await hass.config_entries.flow.async_configure(result["flow_id"], {})
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert result2["type"] == "abort"
|
||||
assert result2["reason"] == "no_devices_found"
|
||||
|
||||
|
||||
async def test_import(hass: HomeAssistant):
|
||||
"""Test import from yaml."""
|
||||
config = {
|
||||
CONF_HOST: IP_ADDRESS,
|
||||
CONF_MAC: MAC_ADDRESS,
|
||||
CONF_NAME: "floor lamp",
|
||||
CONF_PROTOCOL: "ledenet",
|
||||
CONF_MODE: MODE_RGB,
|
||||
CONF_CUSTOM_EFFECT_COLORS: "[255,0,0], [0,0,255]",
|
||||
CONF_CUSTOM_EFFECT_SPEED_PCT: 30,
|
||||
CONF_CUSTOM_EFFECT_TRANSITION: TRANSITION_STROBE,
|
||||
}
|
||||
|
||||
# Success
|
||||
with _patch_discovery(), _patch_wifibulb(), patch(
|
||||
f"{MODULE}.async_setup", return_value=True
|
||||
) as mock_setup, patch(
|
||||
f"{MODULE}.async_setup_entry", return_value=True
|
||||
) as mock_setup_entry:
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN, context={"source": config_entries.SOURCE_IMPORT}, data=config
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert result["type"] == "create_entry"
|
||||
assert result["title"] == "floor lamp"
|
||||
assert result["data"] == {
|
||||
CONF_HOST: IP_ADDRESS,
|
||||
CONF_NAME: "floor lamp",
|
||||
CONF_PROTOCOL: "ledenet",
|
||||
}
|
||||
assert result["options"] == {
|
||||
CONF_MODE: MODE_RGB,
|
||||
CONF_CUSTOM_EFFECT_COLORS: "[255,0,0], [0,0,255]",
|
||||
CONF_CUSTOM_EFFECT_SPEED_PCT: 30,
|
||||
CONF_CUSTOM_EFFECT_TRANSITION: TRANSITION_STROBE,
|
||||
}
|
||||
mock_setup.assert_called_once()
|
||||
mock_setup_entry.assert_called_once()
|
||||
|
||||
# Duplicate
|
||||
with _patch_discovery(), _patch_wifibulb():
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN, context={"source": config_entries.SOURCE_IMPORT}, data=config
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert result["type"] == "abort"
|
||||
assert result["reason"] == "already_configured"
|
||||
|
||||
|
||||
async def test_manual(hass: HomeAssistant):
|
||||
"""Test manually setup."""
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
||||
)
|
||||
assert result["type"] == "form"
|
||||
assert result["step_id"] == "user"
|
||||
assert not result["errors"]
|
||||
|
||||
# Cannot connect (timeout)
|
||||
with _patch_discovery(no_device=True), _patch_wifibulb(no_device=True):
|
||||
result2 = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"], {CONF_HOST: IP_ADDRESS}
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert result2["type"] == "form"
|
||||
assert result2["step_id"] == "user"
|
||||
assert result2["errors"] == {"base": "cannot_connect"}
|
||||
|
||||
# Success
|
||||
with _patch_discovery(), _patch_wifibulb(), patch(
|
||||
f"{MODULE}.async_setup", return_value=True
|
||||
), patch(f"{MODULE}.async_setup_entry", return_value=True):
|
||||
result4 = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"], {CONF_HOST: IP_ADDRESS}
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
assert result4["type"] == "create_entry"
|
||||
assert result4["title"] == IP_ADDRESS
|
||||
assert result4["data"] == {CONF_HOST: IP_ADDRESS, CONF_NAME: IP_ADDRESS}
|
||||
|
||||
# Duplicate
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
||||
)
|
||||
with _patch_discovery(no_device=True), _patch_wifibulb(no_device=True):
|
||||
result2 = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"], {CONF_HOST: IP_ADDRESS}
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert result2["type"] == "abort"
|
||||
assert result2["reason"] == "already_configured"
|
||||
|
||||
|
||||
async def test_manual_no_discovery_data(hass: HomeAssistant):
|
||||
"""Test manually setup without discovery data."""
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
||||
)
|
||||
assert result["type"] == "form"
|
||||
assert result["step_id"] == "user"
|
||||
assert not result["errors"]
|
||||
|
||||
with _patch_discovery(no_device=True), _patch_wifibulb(), patch(
|
||||
f"{MODULE}.async_setup", return_value=True
|
||||
), patch(f"{MODULE}.async_setup_entry", return_value=True):
|
||||
result = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"], {CONF_HOST: IP_ADDRESS}
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert result["type"] == "create_entry"
|
||||
assert result["data"] == {CONF_HOST: IP_ADDRESS, CONF_NAME: IP_ADDRESS}
|
||||
|
||||
|
||||
async def test_discovered_by_discovery_and_dhcp(hass):
|
||||
"""Test we get the form with discovery and abort for dhcp source when we get both."""
|
||||
await setup.async_setup_component(hass, "persistent_notification", {})
|
||||
|
||||
with _patch_discovery(), _patch_wifibulb():
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN,
|
||||
context={"source": config_entries.SOURCE_DISCOVERY},
|
||||
data=FLUX_DISCOVERY,
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
assert result["type"] == RESULT_TYPE_FORM
|
||||
assert result["errors"] is None
|
||||
|
||||
with _patch_discovery(), _patch_wifibulb():
|
||||
result2 = await hass.config_entries.flow.async_init(
|
||||
DOMAIN,
|
||||
context={"source": config_entries.SOURCE_DHCP},
|
||||
data=DHCP_DISCOVERY,
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
assert result2["type"] == RESULT_TYPE_ABORT
|
||||
assert result2["reason"] == "already_in_progress"
|
||||
|
||||
with _patch_discovery(), _patch_wifibulb():
|
||||
result3 = await hass.config_entries.flow.async_init(
|
||||
DOMAIN,
|
||||
context={"source": config_entries.SOURCE_DHCP},
|
||||
data={
|
||||
DHCP_HOSTNAME: "any",
|
||||
DHCP_IP_ADDRESS: IP_ADDRESS,
|
||||
DHCP_MAC_ADDRESS: "00:00:00:00:00:00",
|
||||
},
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
assert result3["type"] == RESULT_TYPE_ABORT
|
||||
assert result3["reason"] == "already_in_progress"
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"source, data",
|
||||
[
|
||||
(config_entries.SOURCE_DHCP, DHCP_DISCOVERY),
|
||||
(config_entries.SOURCE_DISCOVERY, FLUX_DISCOVERY),
|
||||
],
|
||||
)
|
||||
async def test_discovered_by_dhcp_or_discovery(hass, source, data):
|
||||
"""Test we can setup when discovered from dhcp or discovery."""
|
||||
|
||||
await setup.async_setup_component(hass, "persistent_notification", {})
|
||||
|
||||
with _patch_discovery(), _patch_wifibulb():
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN, context={"source": source}, data=data
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert result["type"] == RESULT_TYPE_FORM
|
||||
assert result["errors"] is None
|
||||
|
||||
with _patch_discovery(), _patch_wifibulb(), patch(
|
||||
f"{MODULE}.async_setup", return_value=True
|
||||
) as mock_async_setup, patch(
|
||||
f"{MODULE}.async_setup_entry", return_value=True
|
||||
) as mock_async_setup_entry:
|
||||
result2 = await hass.config_entries.flow.async_configure(result["flow_id"], {})
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert result2["type"] == "create_entry"
|
||||
assert result2["data"] == {CONF_HOST: IP_ADDRESS, CONF_NAME: DEFAULT_ENTRY_TITLE}
|
||||
assert mock_async_setup.called
|
||||
assert mock_async_setup_entry.called
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"source, data",
|
||||
[
|
||||
(config_entries.SOURCE_DHCP, DHCP_DISCOVERY),
|
||||
(config_entries.SOURCE_DISCOVERY, FLUX_DISCOVERY),
|
||||
],
|
||||
)
|
||||
async def test_discovered_by_dhcp_or_discovery_adds_missing_unique_id(
|
||||
hass, source, data
|
||||
):
|
||||
"""Test we can setup when discovered from dhcp or discovery."""
|
||||
config_entry = MockConfigEntry(domain=DOMAIN, data={CONF_HOST: IP_ADDRESS})
|
||||
config_entry.add_to_hass(hass)
|
||||
await setup.async_setup_component(hass, "persistent_notification", {})
|
||||
|
||||
with _patch_discovery(), _patch_wifibulb():
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN, context={"source": source}, data=data
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert result["type"] == RESULT_TYPE_ABORT
|
||||
assert result["reason"] == "already_configured"
|
||||
|
||||
assert config_entry.unique_id == MAC_ADDRESS
|
||||
|
||||
|
||||
async def test_options(hass: HomeAssistant):
|
||||
"""Test options flow."""
|
||||
config_entry = MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
data={CONF_HOST: IP_ADDRESS, CONF_NAME: DEFAULT_ENTRY_TITLE},
|
||||
options={
|
||||
CONF_MODE: MODE_RGB,
|
||||
CONF_CUSTOM_EFFECT_COLORS: "[255,0,0], [0,0,255]",
|
||||
CONF_CUSTOM_EFFECT_SPEED_PCT: 30,
|
||||
CONF_CUSTOM_EFFECT_TRANSITION: TRANSITION_STROBE,
|
||||
},
|
||||
unique_id=MAC_ADDRESS,
|
||||
)
|
||||
config_entry.add_to_hass(hass)
|
||||
|
||||
with _patch_discovery(), _patch_wifibulb():
|
||||
assert await hass.config_entries.async_setup(config_entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
result = await hass.config_entries.options.async_init(config_entry.entry_id)
|
||||
assert result["type"] == "form"
|
||||
assert result["step_id"] == "init"
|
||||
|
||||
user_input = {
|
||||
CONF_MODE: MODE_AUTO,
|
||||
CONF_CUSTOM_EFFECT_COLORS: "[0,0,255], [255,0,0]",
|
||||
CONF_CUSTOM_EFFECT_SPEED_PCT: 50,
|
||||
CONF_CUSTOM_EFFECT_TRANSITION: TRANSITION_JUMP,
|
||||
}
|
||||
with _patch_discovery(), _patch_wifibulb():
|
||||
result2 = await hass.config_entries.options.async_configure(
|
||||
result["flow_id"], user_input
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
assert result2["type"] == "create_entry"
|
||||
assert result2["data"] == user_input
|
||||
assert result2["data"] == config_entry.options
|
||||
assert hass.states.get("light.az120444_aabbccddeeff") is not None
|
58
tests/components/flux_led/test_init.py
Normal file
58
tests/components/flux_led/test_init.py
Normal file
|
@ -0,0 +1,58 @@
|
|||
"""Tests for the flux_led component."""
|
||||
from __future__ import annotations
|
||||
|
||||
from unittest.mock import patch
|
||||
|
||||
from homeassistant.components import flux_led
|
||||
from homeassistant.components.flux_led.const import DOMAIN
|
||||
from homeassistant.config_entries import ConfigEntryState
|
||||
from homeassistant.const import CONF_HOST, EVENT_HOMEASSISTANT_STARTED
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.setup import async_setup_component
|
||||
from homeassistant.util.dt import utcnow
|
||||
|
||||
from . import FLUX_DISCOVERY, IP_ADDRESS, MAC_ADDRESS, _patch_discovery, _patch_wifibulb
|
||||
|
||||
from tests.common import MockConfigEntry, async_fire_time_changed
|
||||
|
||||
|
||||
async def test_configuring_flux_led_causes_discovery(hass: HomeAssistant) -> None:
|
||||
"""Test that specifying empty config does discovery."""
|
||||
with patch("homeassistant.components.flux_led.BulbScanner.scan") as discover:
|
||||
discover.return_value = [FLUX_DISCOVERY]
|
||||
await async_setup_component(hass, flux_led.DOMAIN, {flux_led.DOMAIN: {}})
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert len(discover.mock_calls) == 1
|
||||
hass.bus.async_fire(EVENT_HOMEASSISTANT_STARTED)
|
||||
await hass.async_block_till_done()
|
||||
assert len(discover.mock_calls) == 2
|
||||
|
||||
async_fire_time_changed(hass, utcnow() + flux_led.DISCOVERY_INTERVAL)
|
||||
await hass.async_block_till_done()
|
||||
assert len(discover.mock_calls) == 3
|
||||
|
||||
|
||||
async def test_config_entry_reload(hass: HomeAssistant) -> None:
|
||||
"""Test that a config entry can be reloaded."""
|
||||
config_entry = MockConfigEntry(domain=DOMAIN, data={}, unique_id=MAC_ADDRESS)
|
||||
config_entry.add_to_hass(hass)
|
||||
with _patch_discovery(), _patch_wifibulb():
|
||||
await async_setup_component(hass, flux_led.DOMAIN, {flux_led.DOMAIN: {}})
|
||||
await hass.async_block_till_done()
|
||||
assert config_entry.state == ConfigEntryState.LOADED
|
||||
await hass.config_entries.async_unload(config_entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
assert config_entry.state == ConfigEntryState.NOT_LOADED
|
||||
|
||||
|
||||
async def test_config_entry_retry(hass: HomeAssistant) -> None:
|
||||
"""Test that a config entry can be retried."""
|
||||
config_entry = MockConfigEntry(
|
||||
domain=DOMAIN, data={CONF_HOST: IP_ADDRESS}, unique_id=MAC_ADDRESS
|
||||
)
|
||||
config_entry.add_to_hass(hass)
|
||||
with _patch_discovery(no_device=True), _patch_wifibulb(no_device=True):
|
||||
await async_setup_component(hass, flux_led.DOMAIN, {flux_led.DOMAIN: {}})
|
||||
await hass.async_block_till_done()
|
||||
assert config_entry.state == ConfigEntryState.SETUP_RETRY
|
654
tests/components/flux_led/test_light.py
Normal file
654
tests/components/flux_led/test_light.py
Normal file
|
@ -0,0 +1,654 @@
|
|||
"""Tests for light platform."""
|
||||
from datetime import timedelta
|
||||
|
||||
import pytest
|
||||
|
||||
from homeassistant.components import flux_led
|
||||
from homeassistant.components.flux_led.const import (
|
||||
CONF_COLORS,
|
||||
CONF_CUSTOM_EFFECT,
|
||||
CONF_CUSTOM_EFFECT_COLORS,
|
||||
CONF_CUSTOM_EFFECT_SPEED_PCT,
|
||||
CONF_CUSTOM_EFFECT_TRANSITION,
|
||||
CONF_DEVICES,
|
||||
CONF_SPEED_PCT,
|
||||
CONF_TRANSITION,
|
||||
DOMAIN,
|
||||
MODE_AUTO,
|
||||
TRANSITION_JUMP,
|
||||
)
|
||||
from homeassistant.components.flux_led.light import EFFECT_CUSTOM_CODE, FLUX_EFFECT_LIST
|
||||
from homeassistant.components.light import (
|
||||
ATTR_BRIGHTNESS,
|
||||
ATTR_COLOR_MODE,
|
||||
ATTR_COLOR_TEMP,
|
||||
ATTR_EFFECT,
|
||||
ATTR_EFFECT_LIST,
|
||||
ATTR_HS_COLOR,
|
||||
ATTR_SUPPORTED_COLOR_MODES,
|
||||
DOMAIN as LIGHT_DOMAIN,
|
||||
)
|
||||
from homeassistant.const import (
|
||||
ATTR_ENTITY_ID,
|
||||
CONF_HOST,
|
||||
CONF_MODE,
|
||||
CONF_NAME,
|
||||
CONF_PLATFORM,
|
||||
CONF_PROTOCOL,
|
||||
STATE_OFF,
|
||||
STATE_ON,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import entity_registry as er
|
||||
from homeassistant.setup import async_setup_component
|
||||
from homeassistant.util.dt import utcnow
|
||||
|
||||
from . import (
|
||||
DEFAULT_ENTRY_TITLE,
|
||||
IP_ADDRESS,
|
||||
MAC_ADDRESS,
|
||||
_mocked_bulb,
|
||||
_patch_discovery,
|
||||
_patch_wifibulb,
|
||||
)
|
||||
|
||||
from tests.common import MockConfigEntry, async_fire_time_changed
|
||||
|
||||
|
||||
async def test_light_unique_id(hass: HomeAssistant) -> None:
|
||||
"""Test a light unique id."""
|
||||
config_entry = MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
data={CONF_HOST: IP_ADDRESS, CONF_NAME: DEFAULT_ENTRY_TITLE},
|
||||
unique_id=MAC_ADDRESS,
|
||||
)
|
||||
config_entry.add_to_hass(hass)
|
||||
bulb = _mocked_bulb()
|
||||
with _patch_discovery(device=bulb), _patch_wifibulb(device=bulb):
|
||||
await async_setup_component(hass, flux_led.DOMAIN, {flux_led.DOMAIN: {}})
|
||||
await hass.async_block_till_done()
|
||||
|
||||
entity_id = "light.az120444_aabbccddeeff"
|
||||
entity_registry = er.async_get(hass)
|
||||
assert entity_registry.async_get(entity_id).unique_id == MAC_ADDRESS
|
||||
state = hass.states.get(entity_id)
|
||||
assert state.state == STATE_ON
|
||||
|
||||
|
||||
async def test_light_no_unique_id(hass: HomeAssistant) -> None:
|
||||
"""Test a light without a unique id."""
|
||||
config_entry = MockConfigEntry(
|
||||
domain=DOMAIN, data={CONF_HOST: IP_ADDRESS, CONF_NAME: DEFAULT_ENTRY_TITLE}
|
||||
)
|
||||
config_entry.add_to_hass(hass)
|
||||
bulb = _mocked_bulb()
|
||||
with _patch_discovery(no_device=True), _patch_wifibulb(device=bulb):
|
||||
await async_setup_component(hass, flux_led.DOMAIN, {flux_led.DOMAIN: {}})
|
||||
await hass.async_block_till_done()
|
||||
|
||||
entity_id = "light.az120444_aabbccddeeff"
|
||||
entity_registry = er.async_get(hass)
|
||||
assert entity_registry.async_get(entity_id) is None
|
||||
state = hass.states.get(entity_id)
|
||||
assert state.state == STATE_ON
|
||||
|
||||
|
||||
async def test_rgb_light(hass: HomeAssistant) -> None:
|
||||
"""Test an rgb light."""
|
||||
config_entry = MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
data={CONF_HOST: IP_ADDRESS, CONF_NAME: DEFAULT_ENTRY_TITLE},
|
||||
unique_id=MAC_ADDRESS,
|
||||
)
|
||||
config_entry.add_to_hass(hass)
|
||||
bulb = _mocked_bulb()
|
||||
bulb.rgbwcapable = False
|
||||
bulb.protocol = None
|
||||
with _patch_discovery(device=bulb), _patch_wifibulb(device=bulb):
|
||||
await async_setup_component(hass, flux_led.DOMAIN, {flux_led.DOMAIN: {}})
|
||||
await hass.async_block_till_done()
|
||||
|
||||
entity_id = "light.az120444_aabbccddeeff"
|
||||
|
||||
state = hass.states.get(entity_id)
|
||||
assert state.state == STATE_ON
|
||||
attributes = state.attributes
|
||||
assert attributes[ATTR_BRIGHTNESS] == 128
|
||||
assert attributes[ATTR_COLOR_MODE] == "hs"
|
||||
assert attributes[ATTR_EFFECT_LIST] == FLUX_EFFECT_LIST
|
||||
assert attributes[ATTR_SUPPORTED_COLOR_MODES] == ["hs"]
|
||||
assert attributes[ATTR_HS_COLOR] == (0, 100)
|
||||
|
||||
await hass.services.async_call(
|
||||
LIGHT_DOMAIN, "turn_off", {ATTR_ENTITY_ID: entity_id}, blocking=True
|
||||
)
|
||||
bulb.turnOff.assert_called_once()
|
||||
|
||||
bulb.is_on = False
|
||||
async_fire_time_changed(hass, utcnow() + timedelta(seconds=10))
|
||||
await hass.async_block_till_done()
|
||||
assert hass.states.get(entity_id).state == STATE_OFF
|
||||
|
||||
await hass.services.async_call(
|
||||
LIGHT_DOMAIN, "turn_on", {ATTR_ENTITY_ID: entity_id}, blocking=True
|
||||
)
|
||||
bulb.turnOn.assert_called_once()
|
||||
bulb.turnOn.reset_mock()
|
||||
|
||||
await hass.services.async_call(
|
||||
LIGHT_DOMAIN,
|
||||
"turn_on",
|
||||
{ATTR_ENTITY_ID: entity_id, ATTR_BRIGHTNESS: 100},
|
||||
blocking=True,
|
||||
)
|
||||
bulb.setRgb.assert_called_with(255, 0, 0, brightness=100)
|
||||
bulb.setRgb.reset_mock()
|
||||
|
||||
await hass.services.async_call(
|
||||
LIGHT_DOMAIN,
|
||||
"turn_on",
|
||||
{ATTR_ENTITY_ID: entity_id, ATTR_HS_COLOR: (10, 30)},
|
||||
blocking=True,
|
||||
)
|
||||
bulb.setRgb.assert_called_with(255, 191, 178, brightness=128)
|
||||
bulb.setRgb.reset_mock()
|
||||
|
||||
await hass.services.async_call(
|
||||
LIGHT_DOMAIN,
|
||||
"turn_on",
|
||||
{ATTR_ENTITY_ID: entity_id, ATTR_EFFECT: "random"},
|
||||
blocking=True,
|
||||
)
|
||||
bulb.setRgb.assert_called_once()
|
||||
bulb.setRgb.reset_mock()
|
||||
|
||||
await hass.services.async_call(
|
||||
LIGHT_DOMAIN,
|
||||
"turn_on",
|
||||
{ATTR_ENTITY_ID: entity_id, ATTR_EFFECT: "purple_fade"},
|
||||
blocking=True,
|
||||
)
|
||||
bulb.setPresetPattern.assert_called_with(43, 50)
|
||||
bulb.setPresetPattern.reset_mock()
|
||||
|
||||
|
||||
async def test_rgbw_light(hass: HomeAssistant) -> None:
|
||||
"""Test an rgbw light."""
|
||||
config_entry = MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
data={CONF_HOST: IP_ADDRESS, CONF_NAME: DEFAULT_ENTRY_TITLE},
|
||||
unique_id=MAC_ADDRESS,
|
||||
)
|
||||
config_entry.add_to_hass(hass)
|
||||
bulb = _mocked_bulb()
|
||||
with _patch_discovery(device=bulb), _patch_wifibulb(device=bulb):
|
||||
await async_setup_component(hass, flux_led.DOMAIN, {flux_led.DOMAIN: {}})
|
||||
await hass.async_block_till_done()
|
||||
|
||||
entity_id = "light.az120444_aabbccddeeff"
|
||||
|
||||
state = hass.states.get(entity_id)
|
||||
assert state.state == STATE_ON
|
||||
attributes = state.attributes
|
||||
assert attributes[ATTR_BRIGHTNESS] == 128
|
||||
assert attributes[ATTR_COLOR_MODE] == "rgbw"
|
||||
assert attributes[ATTR_EFFECT_LIST] == FLUX_EFFECT_LIST
|
||||
assert attributes[ATTR_SUPPORTED_COLOR_MODES] == ["color_temp", "hs", "rgbw"]
|
||||
assert attributes[ATTR_HS_COLOR] == (0, 100)
|
||||
|
||||
await hass.services.async_call(
|
||||
LIGHT_DOMAIN, "turn_off", {ATTR_ENTITY_ID: entity_id}, blocking=True
|
||||
)
|
||||
bulb.turnOff.assert_called_once()
|
||||
|
||||
bulb.is_on = False
|
||||
async_fire_time_changed(hass, utcnow() + timedelta(seconds=10))
|
||||
await hass.async_block_till_done()
|
||||
assert hass.states.get(entity_id).state == STATE_OFF
|
||||
|
||||
await hass.services.async_call(
|
||||
LIGHT_DOMAIN, "turn_on", {ATTR_ENTITY_ID: entity_id}, blocking=True
|
||||
)
|
||||
bulb.turnOn.assert_called_once()
|
||||
bulb.turnOn.reset_mock()
|
||||
|
||||
await hass.services.async_call(
|
||||
LIGHT_DOMAIN,
|
||||
"turn_on",
|
||||
{ATTR_ENTITY_ID: entity_id, ATTR_BRIGHTNESS: 100},
|
||||
blocking=True,
|
||||
)
|
||||
bulb.setRgbw.assert_called_with(255, 0, 0, w=50, brightness=100)
|
||||
bulb.setRgbw.reset_mock()
|
||||
|
||||
await hass.services.async_call(
|
||||
LIGHT_DOMAIN,
|
||||
"turn_on",
|
||||
{ATTR_ENTITY_ID: entity_id, ATTR_COLOR_TEMP: 150},
|
||||
blocking=True,
|
||||
)
|
||||
bulb.setRgbw.assert_called_with(w2=128)
|
||||
bulb.setRgbw.reset_mock()
|
||||
|
||||
await hass.services.async_call(
|
||||
LIGHT_DOMAIN,
|
||||
"turn_on",
|
||||
{ATTR_ENTITY_ID: entity_id, ATTR_COLOR_TEMP: 290},
|
||||
blocking=True,
|
||||
)
|
||||
bulb.setRgbw.assert_called_with(w=128)
|
||||
bulb.setRgbw.reset_mock()
|
||||
|
||||
await hass.services.async_call(
|
||||
LIGHT_DOMAIN,
|
||||
"turn_on",
|
||||
{ATTR_ENTITY_ID: entity_id, ATTR_HS_COLOR: (10, 30)},
|
||||
blocking=True,
|
||||
)
|
||||
bulb.setRgbw.assert_called_with(255, 191, 178, w=50, brightness=128)
|
||||
bulb.setRgbw.reset_mock()
|
||||
|
||||
await hass.services.async_call(
|
||||
LIGHT_DOMAIN,
|
||||
"turn_on",
|
||||
{ATTR_ENTITY_ID: entity_id, ATTR_EFFECT: "random"},
|
||||
blocking=True,
|
||||
)
|
||||
bulb.setRgb.assert_called_once()
|
||||
bulb.setRgb.reset_mock()
|
||||
|
||||
await hass.services.async_call(
|
||||
LIGHT_DOMAIN,
|
||||
"turn_on",
|
||||
{ATTR_ENTITY_ID: entity_id, ATTR_EFFECT: "purple_fade"},
|
||||
blocking=True,
|
||||
)
|
||||
bulb.setPresetPattern.assert_called_with(43, 50)
|
||||
bulb.setPresetPattern.reset_mock()
|
||||
|
||||
|
||||
async def test_rgbcw_light(hass: HomeAssistant) -> None:
|
||||
"""Test an rgbcw light."""
|
||||
config_entry = MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
data={CONF_HOST: IP_ADDRESS, CONF_NAME: DEFAULT_ENTRY_TITLE},
|
||||
unique_id=MAC_ADDRESS,
|
||||
)
|
||||
config_entry.add_to_hass(hass)
|
||||
bulb = _mocked_bulb()
|
||||
bulb.raw_state = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
bulb.raw_state[9] = 1
|
||||
bulb.raw_state[11] = 2
|
||||
|
||||
with _patch_discovery(device=bulb), _patch_wifibulb(device=bulb):
|
||||
await async_setup_component(hass, flux_led.DOMAIN, {flux_led.DOMAIN: {}})
|
||||
await hass.async_block_till_done()
|
||||
|
||||
entity_id = "light.az120444_aabbccddeeff"
|
||||
|
||||
state = hass.states.get(entity_id)
|
||||
assert state.state == STATE_ON
|
||||
attributes = state.attributes
|
||||
assert attributes[ATTR_BRIGHTNESS] == 128
|
||||
assert attributes[ATTR_COLOR_MODE] == "rgbw"
|
||||
assert attributes[ATTR_EFFECT_LIST] == FLUX_EFFECT_LIST
|
||||
assert attributes[ATTR_SUPPORTED_COLOR_MODES] == ["color_temp", "hs", "rgbw"]
|
||||
assert attributes[ATTR_HS_COLOR] == (0, 100)
|
||||
|
||||
await hass.services.async_call(
|
||||
LIGHT_DOMAIN, "turn_off", {ATTR_ENTITY_ID: entity_id}, blocking=True
|
||||
)
|
||||
bulb.turnOff.assert_called_once()
|
||||
|
||||
bulb.is_on = False
|
||||
async_fire_time_changed(hass, utcnow() + timedelta(seconds=10))
|
||||
await hass.async_block_till_done()
|
||||
assert hass.states.get(entity_id).state == STATE_OFF
|
||||
|
||||
await hass.services.async_call(
|
||||
LIGHT_DOMAIN, "turn_on", {ATTR_ENTITY_ID: entity_id}, blocking=True
|
||||
)
|
||||
bulb.turnOn.assert_called_once()
|
||||
bulb.turnOn.reset_mock()
|
||||
|
||||
await hass.services.async_call(
|
||||
LIGHT_DOMAIN,
|
||||
"turn_on",
|
||||
{ATTR_ENTITY_ID: entity_id, ATTR_BRIGHTNESS: 100},
|
||||
blocking=True,
|
||||
)
|
||||
bulb.setRgbw.assert_called_with(255, 0, 0, w=50, brightness=100)
|
||||
bulb.setRgbw.reset_mock()
|
||||
|
||||
await hass.services.async_call(
|
||||
LIGHT_DOMAIN,
|
||||
"turn_on",
|
||||
{ATTR_ENTITY_ID: entity_id, ATTR_COLOR_TEMP: 150},
|
||||
blocking=True,
|
||||
)
|
||||
bulb.setRgbw.assert_called_with(w2=128)
|
||||
bulb.setRgbw.reset_mock()
|
||||
|
||||
await hass.services.async_call(
|
||||
LIGHT_DOMAIN,
|
||||
"turn_on",
|
||||
{ATTR_ENTITY_ID: entity_id, ATTR_COLOR_TEMP: 290},
|
||||
blocking=True,
|
||||
)
|
||||
bulb.setRgbw.assert_called_with(w=128)
|
||||
bulb.setRgbw.reset_mock()
|
||||
|
||||
await hass.services.async_call(
|
||||
LIGHT_DOMAIN,
|
||||
"turn_on",
|
||||
{ATTR_ENTITY_ID: entity_id, ATTR_HS_COLOR: (10, 30)},
|
||||
blocking=True,
|
||||
)
|
||||
bulb.setRgbw.assert_called_with(255, 191, 178, w=50, brightness=128)
|
||||
bulb.setRgbw.reset_mock()
|
||||
|
||||
await hass.services.async_call(
|
||||
LIGHT_DOMAIN,
|
||||
"turn_on",
|
||||
{ATTR_ENTITY_ID: entity_id, ATTR_EFFECT: "random"},
|
||||
blocking=True,
|
||||
)
|
||||
bulb.setRgb.assert_called_once()
|
||||
bulb.setRgb.reset_mock()
|
||||
|
||||
await hass.services.async_call(
|
||||
LIGHT_DOMAIN,
|
||||
"turn_on",
|
||||
{ATTR_ENTITY_ID: entity_id, ATTR_EFFECT: "purple_fade"},
|
||||
blocking=True,
|
||||
)
|
||||
bulb.setPresetPattern.assert_called_with(43, 50)
|
||||
bulb.setPresetPattern.reset_mock()
|
||||
|
||||
|
||||
async def test_white_light(hass: HomeAssistant) -> None:
|
||||
"""Test a white light."""
|
||||
config_entry = MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
data={CONF_HOST: IP_ADDRESS, CONF_NAME: DEFAULT_ENTRY_TITLE},
|
||||
unique_id=MAC_ADDRESS,
|
||||
)
|
||||
config_entry.add_to_hass(hass)
|
||||
bulb = _mocked_bulb()
|
||||
bulb.mode = "ww"
|
||||
bulb.protocol = None
|
||||
with _patch_discovery(device=bulb), _patch_wifibulb(device=bulb):
|
||||
await async_setup_component(hass, flux_led.DOMAIN, {flux_led.DOMAIN: {}})
|
||||
await hass.async_block_till_done()
|
||||
|
||||
entity_id = "light.az120444_aabbccddeeff"
|
||||
|
||||
state = hass.states.get(entity_id)
|
||||
assert state.state == STATE_ON
|
||||
attributes = state.attributes
|
||||
assert attributes[ATTR_BRIGHTNESS] == 50
|
||||
assert attributes[ATTR_COLOR_MODE] == "brightness"
|
||||
assert attributes[ATTR_SUPPORTED_COLOR_MODES] == ["brightness"]
|
||||
|
||||
await hass.services.async_call(
|
||||
LIGHT_DOMAIN, "turn_off", {ATTR_ENTITY_ID: entity_id}, blocking=True
|
||||
)
|
||||
bulb.turnOff.assert_called_once()
|
||||
|
||||
bulb.is_on = False
|
||||
async_fire_time_changed(hass, utcnow() + timedelta(seconds=10))
|
||||
await hass.async_block_till_done()
|
||||
assert hass.states.get(entity_id).state == STATE_OFF
|
||||
|
||||
await hass.services.async_call(
|
||||
LIGHT_DOMAIN, "turn_on", {ATTR_ENTITY_ID: entity_id}, blocking=True
|
||||
)
|
||||
bulb.turnOn.assert_called_once()
|
||||
bulb.turnOn.reset_mock()
|
||||
|
||||
await hass.services.async_call(
|
||||
LIGHT_DOMAIN,
|
||||
"turn_on",
|
||||
{ATTR_ENTITY_ID: entity_id, ATTR_BRIGHTNESS: 100},
|
||||
blocking=True,
|
||||
)
|
||||
bulb.setRgbw.assert_called_with(0, 0, 0, w=100)
|
||||
bulb.setRgbw.reset_mock()
|
||||
|
||||
|
||||
async def test_rgb_light_custom_effects(
|
||||
hass: HomeAssistant, caplog: pytest.LogCaptureFixture
|
||||
) -> None:
|
||||
"""Test an rgb light with a custom effect."""
|
||||
config_entry = MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
data={CONF_HOST: IP_ADDRESS, CONF_NAME: DEFAULT_ENTRY_TITLE},
|
||||
unique_id=MAC_ADDRESS,
|
||||
options={
|
||||
CONF_MODE: MODE_AUTO,
|
||||
CONF_CUSTOM_EFFECT_COLORS: "[0,0,255], [255,0,0]",
|
||||
CONF_CUSTOM_EFFECT_SPEED_PCT: 88,
|
||||
CONF_CUSTOM_EFFECT_TRANSITION: TRANSITION_JUMP,
|
||||
},
|
||||
)
|
||||
config_entry.add_to_hass(hass)
|
||||
bulb = _mocked_bulb()
|
||||
with _patch_discovery(device=bulb), _patch_wifibulb(device=bulb):
|
||||
await async_setup_component(hass, flux_led.DOMAIN, {flux_led.DOMAIN: {}})
|
||||
await hass.async_block_till_done()
|
||||
|
||||
entity_id = "light.az120444_aabbccddeeff"
|
||||
|
||||
state = hass.states.get(entity_id)
|
||||
assert state.state == STATE_ON
|
||||
attributes = state.attributes
|
||||
assert attributes[ATTR_BRIGHTNESS] == 128
|
||||
assert attributes[ATTR_COLOR_MODE] == "rgbw"
|
||||
assert attributes[ATTR_EFFECT_LIST] == [*FLUX_EFFECT_LIST, "custom"]
|
||||
assert attributes[ATTR_SUPPORTED_COLOR_MODES] == ["color_temp", "hs", "rgbw"]
|
||||
assert attributes[ATTR_HS_COLOR] == (0, 100)
|
||||
|
||||
await hass.services.async_call(
|
||||
LIGHT_DOMAIN, "turn_off", {ATTR_ENTITY_ID: entity_id}, blocking=True
|
||||
)
|
||||
bulb.turnOff.assert_called_once()
|
||||
|
||||
bulb.is_on = False
|
||||
async_fire_time_changed(hass, utcnow() + timedelta(seconds=10))
|
||||
await hass.async_block_till_done()
|
||||
assert hass.states.get(entity_id).state == STATE_OFF
|
||||
|
||||
await hass.services.async_call(
|
||||
LIGHT_DOMAIN,
|
||||
"turn_on",
|
||||
{ATTR_ENTITY_ID: entity_id, ATTR_EFFECT: "custom"},
|
||||
blocking=True,
|
||||
)
|
||||
bulb.setCustomPattern.assert_called_with([[0, 0, 255], [255, 0, 0]], 88, "jump")
|
||||
bulb.setCustomPattern.reset_mock()
|
||||
bulb.raw_state = [0, 0, 0, EFFECT_CUSTOM_CODE, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
bulb.is_on = True
|
||||
async_fire_time_changed(hass, utcnow() + timedelta(seconds=20))
|
||||
await hass.async_block_till_done()
|
||||
state = hass.states.get(entity_id)
|
||||
assert state.state == STATE_ON
|
||||
attributes = state.attributes
|
||||
assert attributes[ATTR_EFFECT] == "custom"
|
||||
|
||||
caplog.clear()
|
||||
await hass.services.async_call(
|
||||
LIGHT_DOMAIN,
|
||||
"turn_on",
|
||||
{ATTR_ENTITY_ID: entity_id, ATTR_BRIGHTNESS: 55, ATTR_EFFECT: "custom"},
|
||||
blocking=True,
|
||||
)
|
||||
bulb.setCustomPattern.assert_called_with([[0, 0, 255], [255, 0, 0]], 88, "jump")
|
||||
bulb.setCustomPattern.reset_mock()
|
||||
bulb.raw_state = [0, 0, 0, EFFECT_CUSTOM_CODE, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
bulb.is_on = True
|
||||
async_fire_time_changed(hass, utcnow() + timedelta(seconds=20))
|
||||
await hass.async_block_till_done()
|
||||
state = hass.states.get(entity_id)
|
||||
assert state.state == STATE_ON
|
||||
attributes = state.attributes
|
||||
assert attributes[ATTR_EFFECT] == "custom"
|
||||
assert "RGB, brightness and white level are ignored when" in caplog.text
|
||||
|
||||
|
||||
async def test_rgb_light_custom_effects_invalid_colors(hass: HomeAssistant) -> None:
|
||||
"""Test an rgb light with a invalid effect."""
|
||||
config_entry = MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
data={CONF_HOST: IP_ADDRESS, CONF_NAME: DEFAULT_ENTRY_TITLE},
|
||||
unique_id=MAC_ADDRESS,
|
||||
options={
|
||||
CONF_MODE: MODE_AUTO,
|
||||
CONF_CUSTOM_EFFECT_COLORS: ":: CANNOT BE PARSED ::",
|
||||
CONF_CUSTOM_EFFECT_SPEED_PCT: 88,
|
||||
CONF_CUSTOM_EFFECT_TRANSITION: TRANSITION_JUMP,
|
||||
},
|
||||
)
|
||||
config_entry.add_to_hass(hass)
|
||||
bulb = _mocked_bulb()
|
||||
with _patch_discovery(device=bulb), _patch_wifibulb(device=bulb):
|
||||
await async_setup_component(hass, flux_led.DOMAIN, {flux_led.DOMAIN: {}})
|
||||
await hass.async_block_till_done()
|
||||
|
||||
entity_id = "light.az120444_aabbccddeeff"
|
||||
|
||||
state = hass.states.get(entity_id)
|
||||
assert state.state == STATE_ON
|
||||
attributes = state.attributes
|
||||
assert attributes[ATTR_BRIGHTNESS] == 128
|
||||
assert attributes[ATTR_COLOR_MODE] == "rgbw"
|
||||
assert attributes[ATTR_EFFECT_LIST] == FLUX_EFFECT_LIST
|
||||
assert attributes[ATTR_SUPPORTED_COLOR_MODES] == ["color_temp", "hs", "rgbw"]
|
||||
assert attributes[ATTR_HS_COLOR] == (0, 100)
|
||||
|
||||
|
||||
async def test_rgb_light_custom_effect_via_service(
|
||||
hass: HomeAssistant, caplog: pytest.LogCaptureFixture
|
||||
) -> None:
|
||||
"""Test an rgb light with a custom effect set via the service."""
|
||||
config_entry = MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
data={CONF_HOST: IP_ADDRESS, CONF_NAME: DEFAULT_ENTRY_TITLE},
|
||||
unique_id=MAC_ADDRESS,
|
||||
)
|
||||
config_entry.add_to_hass(hass)
|
||||
bulb = _mocked_bulb()
|
||||
with _patch_discovery(device=bulb), _patch_wifibulb(device=bulb):
|
||||
await async_setup_component(hass, flux_led.DOMAIN, {flux_led.DOMAIN: {}})
|
||||
await hass.async_block_till_done()
|
||||
|
||||
entity_id = "light.az120444_aabbccddeeff"
|
||||
|
||||
state = hass.states.get(entity_id)
|
||||
assert state.state == STATE_ON
|
||||
attributes = state.attributes
|
||||
assert attributes[ATTR_BRIGHTNESS] == 128
|
||||
assert attributes[ATTR_COLOR_MODE] == "rgbw"
|
||||
assert attributes[ATTR_EFFECT_LIST] == [*FLUX_EFFECT_LIST]
|
||||
assert attributes[ATTR_SUPPORTED_COLOR_MODES] == ["color_temp", "hs", "rgbw"]
|
||||
assert attributes[ATTR_HS_COLOR] == (0, 100)
|
||||
|
||||
await hass.services.async_call(
|
||||
LIGHT_DOMAIN, "turn_off", {ATTR_ENTITY_ID: entity_id}, blocking=True
|
||||
)
|
||||
bulb.turnOff.assert_called_once()
|
||||
|
||||
bulb.is_on = False
|
||||
async_fire_time_changed(hass, utcnow() + timedelta(seconds=10))
|
||||
await hass.async_block_till_done()
|
||||
assert hass.states.get(entity_id).state == STATE_OFF
|
||||
|
||||
await hass.services.async_call(
|
||||
DOMAIN,
|
||||
"set_custom_effect",
|
||||
{
|
||||
ATTR_ENTITY_ID: entity_id,
|
||||
CONF_COLORS: [[0, 0, 255], [255, 0, 0]],
|
||||
CONF_SPEED_PCT: 30,
|
||||
CONF_TRANSITION: "jump",
|
||||
},
|
||||
blocking=True,
|
||||
)
|
||||
bulb.setCustomPattern.assert_called_with([(0, 0, 255), (255, 0, 0)], 30, "jump")
|
||||
bulb.setCustomPattern.reset_mock()
|
||||
|
||||
|
||||
async def test_rgbw_detection_without_protocol(hass: HomeAssistant) -> None:
|
||||
"""Test an rgbw detection without protocol."""
|
||||
config_entry = MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
data={CONF_HOST: IP_ADDRESS, CONF_NAME: DEFAULT_ENTRY_TITLE},
|
||||
unique_id=MAC_ADDRESS,
|
||||
)
|
||||
config_entry.add_to_hass(hass)
|
||||
bulb = _mocked_bulb()
|
||||
bulb.protocol = None
|
||||
bulb.rgbwprotocol = None
|
||||
bulb.rgbwcapable = True
|
||||
with _patch_discovery(device=bulb), _patch_wifibulb(device=bulb):
|
||||
await async_setup_component(hass, flux_led.DOMAIN, {flux_led.DOMAIN: {}})
|
||||
await hass.async_block_till_done()
|
||||
|
||||
entity_id = "light.az120444_aabbccddeeff"
|
||||
|
||||
state = hass.states.get(entity_id)
|
||||
assert state.state == STATE_ON
|
||||
attributes = state.attributes
|
||||
assert attributes[ATTR_BRIGHTNESS] == 128
|
||||
assert attributes[ATTR_COLOR_MODE] == "rgbw"
|
||||
assert attributes[ATTR_EFFECT_LIST] == FLUX_EFFECT_LIST
|
||||
assert attributes[ATTR_SUPPORTED_COLOR_MODES] == ["color_temp", "hs", "rgbw"]
|
||||
assert attributes[ATTR_HS_COLOR] == (0, 100)
|
||||
|
||||
|
||||
async def test_migrate_from_yaml(hass: HomeAssistant) -> None:
|
||||
"""Test migrate from yaml."""
|
||||
config = {
|
||||
LIGHT_DOMAIN: [
|
||||
{
|
||||
CONF_PLATFORM: DOMAIN,
|
||||
CONF_DEVICES: {
|
||||
IP_ADDRESS: {
|
||||
CONF_NAME: "flux_lamppost",
|
||||
CONF_PROTOCOL: "ledenet",
|
||||
CONF_CUSTOM_EFFECT: {
|
||||
CONF_SPEED_PCT: 30,
|
||||
CONF_TRANSITION: "strobe",
|
||||
CONF_COLORS: [[255, 0, 0], [255, 255, 0], [0, 255, 0]],
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
],
|
||||
}
|
||||
with _patch_discovery(), _patch_wifibulb():
|
||||
await async_setup_component(hass, LIGHT_DOMAIN, config)
|
||||
await hass.async_block_till_done()
|
||||
await hass.async_block_till_done()
|
||||
await hass.async_block_till_done()
|
||||
|
||||
entries = hass.config_entries.async_entries(DOMAIN)
|
||||
assert entries
|
||||
|
||||
migrated_entry = None
|
||||
for entry in entries:
|
||||
if entry.unique_id == MAC_ADDRESS:
|
||||
migrated_entry = entry
|
||||
break
|
||||
|
||||
assert migrated_entry is not None
|
||||
assert migrated_entry.data == {
|
||||
CONF_HOST: IP_ADDRESS,
|
||||
CONF_NAME: "flux_lamppost",
|
||||
CONF_PROTOCOL: "ledenet",
|
||||
}
|
||||
assert migrated_entry.options == {
|
||||
CONF_MODE: "auto",
|
||||
CONF_CUSTOM_EFFECT_COLORS: "[(255, 0, 0), (255, 255, 0), (0, 255, 0)]",
|
||||
CONF_CUSTOM_EFFECT_SPEED_PCT: 30,
|
||||
CONF_CUSTOM_EFFECT_TRANSITION: "strobe",
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue