mirror of
https://github.com/home-assistant/core.git
synced 2025-07-28 23:57:06 +00:00
Refactor yeelight integration to use only flows (#51255)
* Refactor light.py to use only flows.py, eliminating transitions.py * Reformat yeelight source code using black
This commit is contained in:
parent
549b0b0727
commit
3c452f8c9b
@ -164,16 +164,11 @@ async def async_setup(hass: HomeAssistant, config: dict) -> bool:
|
||||
# Import manually configured devices
|
||||
for host, device_config in config.get(DOMAIN, {}).get(CONF_DEVICES, {}).items():
|
||||
_LOGGER.debug("Importing configured %s", host)
|
||||
entry_config = {
|
||||
CONF_HOST: host,
|
||||
**device_config,
|
||||
}
|
||||
entry_config = {CONF_HOST: host, **device_config}
|
||||
hass.async_create_task(
|
||||
hass.config_entries.flow.async_init(
|
||||
DOMAIN,
|
||||
context={"source": SOURCE_IMPORT},
|
||||
data=entry_config,
|
||||
),
|
||||
DOMAIN, context={"source": SOURCE_IMPORT}, data=entry_config
|
||||
)
|
||||
)
|
||||
|
||||
return True
|
||||
@ -203,9 +198,7 @@ async def _async_initialize(
|
||||
|
||||
entry.async_on_unload(
|
||||
async_dispatcher_connect(
|
||||
hass,
|
||||
DEVICE_INITIALIZED.format(host),
|
||||
_async_load_platforms,
|
||||
hass, DEVICE_INITIALIZED.format(host), _async_load_platforms
|
||||
)
|
||||
)
|
||||
|
||||
@ -224,10 +217,7 @@ def _async_populate_entry_options(hass: HomeAssistant, entry: ConfigEntry) -> No
|
||||
|
||||
hass.config_entries.async_update_entry(
|
||||
entry,
|
||||
data={
|
||||
CONF_HOST: entry.data.get(CONF_HOST),
|
||||
CONF_ID: entry.data.get(CONF_ID),
|
||||
},
|
||||
data={CONF_HOST: entry.data.get(CONF_HOST), CONF_ID: entry.data.get(CONF_ID)},
|
||||
options={
|
||||
CONF_NAME: entry.data.get(CONF_NAME, ""),
|
||||
CONF_MODEL: entry.data.get(CONF_MODEL, ""),
|
||||
@ -613,9 +603,7 @@ class YeelightEntity(Entity):
|
||||
|
||||
|
||||
async def _async_get_device(
|
||||
hass: HomeAssistant,
|
||||
host: str,
|
||||
entry: ConfigEntry,
|
||||
hass: HomeAssistant, host: str, entry: ConfigEntry
|
||||
) -> YeelightDevice:
|
||||
# Get model from config and capabilities
|
||||
model = entry.options.get(CONF_MODEL)
|
||||
|
@ -83,10 +83,7 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
||||
)
|
||||
|
||||
self._set_confirm_only()
|
||||
placeholders = {
|
||||
"model": self._discovered_model,
|
||||
"host": self._discovered_ip,
|
||||
}
|
||||
placeholders = {"model": self._discovered_model, "host": self._discovered_ip}
|
||||
self.context["title_placeholders"] = placeholders
|
||||
return self.async_show_form(
|
||||
step_id="discovery_confirm", description_placeholders=placeholders
|
||||
@ -105,8 +102,7 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
||||
else:
|
||||
self._abort_if_unique_id_configured()
|
||||
return self.async_create_entry(
|
||||
title=f"{model} {self.unique_id}",
|
||||
data=user_input,
|
||||
title=f"{model} {self.unique_id}", data=user_input
|
||||
)
|
||||
|
||||
user_input = user_input or {}
|
||||
@ -126,8 +122,7 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
||||
await self.async_set_unique_id(unique_id)
|
||||
self._abort_if_unique_id_configured()
|
||||
return self.async_create_entry(
|
||||
title=_async_unique_name(capabilities),
|
||||
data={CONF_ID: unique_id},
|
||||
title=_async_unique_name(capabilities), data={CONF_ID: unique_id}
|
||||
)
|
||||
|
||||
configured_devices = {
|
||||
@ -223,19 +218,16 @@ class OptionsFlowHandler(config_entries.OptionsFlow):
|
||||
{
|
||||
vol.Optional(CONF_MODEL, default=options[CONF_MODEL]): str,
|
||||
vol.Required(
|
||||
CONF_TRANSITION,
|
||||
default=options[CONF_TRANSITION],
|
||||
CONF_TRANSITION, default=options[CONF_TRANSITION]
|
||||
): cv.positive_int,
|
||||
vol.Required(
|
||||
CONF_MODE_MUSIC, default=options[CONF_MODE_MUSIC]
|
||||
): bool,
|
||||
vol.Required(
|
||||
CONF_SAVE_ON_CHANGE,
|
||||
default=options[CONF_SAVE_ON_CHANGE],
|
||||
CONF_SAVE_ON_CHANGE, default=options[CONF_SAVE_ON_CHANGE]
|
||||
): bool,
|
||||
vol.Required(
|
||||
CONF_NIGHTLIGHT_SWITCH,
|
||||
default=options[CONF_NIGHTLIGHT_SWITCH],
|
||||
CONF_NIGHTLIGHT_SWITCH, default=options[CONF_NIGHTLIGHT_SWITCH]
|
||||
): bool,
|
||||
}
|
||||
),
|
||||
|
@ -6,15 +6,7 @@ import logging
|
||||
|
||||
import voluptuous as vol
|
||||
import yeelight
|
||||
from yeelight import (
|
||||
Bulb,
|
||||
BulbException,
|
||||
Flow,
|
||||
RGBTransition,
|
||||
SleepTransition,
|
||||
flows,
|
||||
transitions as yee_transitions,
|
||||
)
|
||||
from yeelight import Bulb, BulbException, Flow, RGBTransition, SleepTransition, flows
|
||||
from yeelight.enums import BulbType, LightType, PowerMode, SceneClass
|
||||
|
||||
from homeassistant.components.light import (
|
||||
@ -180,9 +172,7 @@ SERVICE_SCHEMA_SET_MODE = {
|
||||
vol.Required(ATTR_MODE): vol.In([mode.name.lower() for mode in PowerMode])
|
||||
}
|
||||
|
||||
SERVICE_SCHEMA_SET_MUSIC_MODE = {
|
||||
vol.Required(ATTR_MODE_MUSIC): cv.boolean,
|
||||
}
|
||||
SERVICE_SCHEMA_SET_MUSIC_MODE = {vol.Required(ATTR_MODE_MUSIC): cv.boolean}
|
||||
|
||||
SERVICE_SCHEMA_START_FLOW = YEELIGHT_FLOW_TRANSITION_SCHEMA
|
||||
|
||||
@ -358,11 +348,7 @@ def _async_setup_services(hass: HomeAssistant):
|
||||
transitions=_transitions_config_parser(service_call.data[ATTR_TRANSITIONS]),
|
||||
)
|
||||
await hass.async_add_executor_job(
|
||||
partial(
|
||||
entity.set_scene,
|
||||
SceneClass.CF,
|
||||
flow,
|
||||
)
|
||||
partial(entity.set_scene, SceneClass.CF, flow)
|
||||
)
|
||||
|
||||
async def _async_set_auto_delay_off_scene(entity, service_call):
|
||||
@ -378,24 +364,16 @@ def _async_setup_services(hass: HomeAssistant):
|
||||
platform = entity_platform.async_get_current_platform()
|
||||
|
||||
platform.async_register_entity_service(
|
||||
SERVICE_SET_MODE,
|
||||
SERVICE_SCHEMA_SET_MODE,
|
||||
"set_mode",
|
||||
SERVICE_SET_MODE, SERVICE_SCHEMA_SET_MODE, "set_mode"
|
||||
)
|
||||
platform.async_register_entity_service(
|
||||
SERVICE_START_FLOW,
|
||||
SERVICE_SCHEMA_START_FLOW,
|
||||
_async_start_flow,
|
||||
SERVICE_START_FLOW, SERVICE_SCHEMA_START_FLOW, _async_start_flow
|
||||
)
|
||||
platform.async_register_entity_service(
|
||||
SERVICE_SET_COLOR_SCENE,
|
||||
SERVICE_SCHEMA_SET_COLOR_SCENE,
|
||||
_async_set_color_scene,
|
||||
SERVICE_SET_COLOR_SCENE, SERVICE_SCHEMA_SET_COLOR_SCENE, _async_set_color_scene
|
||||
)
|
||||
platform.async_register_entity_service(
|
||||
SERVICE_SET_HSV_SCENE,
|
||||
SERVICE_SCHEMA_SET_HSV_SCENE,
|
||||
_async_set_hsv_scene,
|
||||
SERVICE_SET_HSV_SCENE, SERVICE_SCHEMA_SET_HSV_SCENE, _async_set_hsv_scene
|
||||
)
|
||||
platform.async_register_entity_service(
|
||||
SERVICE_SET_COLOR_TEMP_SCENE,
|
||||
@ -413,9 +391,7 @@ def _async_setup_services(hass: HomeAssistant):
|
||||
_async_set_auto_delay_off_scene,
|
||||
)
|
||||
platform.async_register_entity_service(
|
||||
SERVICE_SET_MUSIC_MODE,
|
||||
SERVICE_SCHEMA_SET_MUSIC_MODE,
|
||||
"set_music_mode",
|
||||
SERVICE_SET_MUSIC_MODE, SERVICE_SCHEMA_SET_MUSIC_MODE, "set_music_mode"
|
||||
)
|
||||
|
||||
|
||||
@ -707,11 +683,11 @@ class YeelightGenericLight(YeelightEntity, LightEntity):
|
||||
elif effect == EFFECT_FAST_RANDOM_LOOP:
|
||||
flow = flows.random_loop(duration=250)
|
||||
elif effect == EFFECT_WHATSAPP:
|
||||
flow = Flow(count=2, transitions=yee_transitions.pulse(37, 211, 102))
|
||||
flow = flows.pulse(37, 211, 102, count=2)
|
||||
elif effect == EFFECT_FACEBOOK:
|
||||
flow = Flow(count=2, transitions=yee_transitions.pulse(59, 89, 152))
|
||||
flow = flows.pulse(59, 89, 152, count=2)
|
||||
elif effect == EFFECT_TWITTER:
|
||||
flow = Flow(count=2, transitions=yee_transitions.pulse(0, 172, 237))
|
||||
flow = flows.pulse(0, 172, 237, count=2)
|
||||
else:
|
||||
return
|
||||
|
||||
|
@ -74,9 +74,7 @@ YAML_CONFIGURATION = {
|
||||
}
|
||||
}
|
||||
|
||||
CONFIG_ENTRY_DATA = {
|
||||
CONF_ID: ID,
|
||||
}
|
||||
CONFIG_ENTRY_DATA = {CONF_ID: ID}
|
||||
|
||||
|
||||
def _mocked_bulb(cannot_connect=False):
|
||||
|
@ -56,17 +56,13 @@ async def test_discovery(hass: HomeAssistant):
|
||||
assert not result["errors"]
|
||||
|
||||
with _patch_discovery(f"{MODULE_CONFIG_FLOW}.yeelight"):
|
||||
result2 = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"],
|
||||
{},
|
||||
)
|
||||
result2 = await hass.config_entries.flow.async_configure(result["flow_id"], {})
|
||||
assert result2["type"] == "form"
|
||||
assert result2["step_id"] == "pick_device"
|
||||
assert not result2["errors"]
|
||||
|
||||
with patch(f"{MODULE}.async_setup", return_value=True) as mock_setup, patch(
|
||||
f"{MODULE}.async_setup_entry",
|
||||
return_value=True,
|
||||
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: ID}
|
||||
@ -87,10 +83,7 @@ async def test_discovery(hass: HomeAssistant):
|
||||
assert not result["errors"]
|
||||
|
||||
with _patch_discovery(f"{MODULE_CONFIG_FLOW}.yeelight"):
|
||||
result2 = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"],
|
||||
{},
|
||||
)
|
||||
result2 = await hass.config_entries.flow.async_configure(result["flow_id"], {})
|
||||
assert result2["type"] == "abort"
|
||||
assert result2["reason"] == "no_devices_found"
|
||||
|
||||
@ -102,10 +95,7 @@ async def test_discovery_no_device(hass: HomeAssistant):
|
||||
)
|
||||
|
||||
with _patch_discovery(f"{MODULE_CONFIG_FLOW}.yeelight", no_device=True):
|
||||
result2 = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"],
|
||||
{},
|
||||
)
|
||||
result2 = await hass.config_entries.flow.async_configure(result["flow_id"], {})
|
||||
|
||||
assert result2["type"] == "abort"
|
||||
assert result2["reason"] == "no_devices_found"
|
||||
@ -138,8 +128,7 @@ async def test_import(hass: HomeAssistant):
|
||||
with patch(f"{MODULE_CONFIG_FLOW}.yeelight.Bulb", return_value=mocked_bulb), patch(
|
||||
f"{MODULE}.async_setup", return_value=True
|
||||
) as mock_setup, patch(
|
||||
f"{MODULE}.async_setup_entry",
|
||||
return_value=True,
|
||||
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
|
||||
@ -200,10 +189,7 @@ async def test_manual(hass: HomeAssistant):
|
||||
mocked_bulb = _mocked_bulb()
|
||||
with patch(f"{MODULE_CONFIG_FLOW}.yeelight.Bulb", return_value=mocked_bulb), patch(
|
||||
f"{MODULE}.async_setup", return_value=True
|
||||
), patch(
|
||||
f"{MODULE}.async_setup_entry",
|
||||
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}
|
||||
)
|
||||
@ -279,10 +265,7 @@ async def test_manual_no_capabilities(hass: HomeAssistant):
|
||||
type(mocked_bulb).get_capabilities = MagicMock(return_value=None)
|
||||
with patch(f"{MODULE_CONFIG_FLOW}.yeelight.Bulb", return_value=mocked_bulb), patch(
|
||||
f"{MODULE}.async_setup", return_value=True
|
||||
), patch(
|
||||
f"{MODULE}.async_setup_entry",
|
||||
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}
|
||||
)
|
||||
@ -354,16 +337,13 @@ async def test_discovered_by_dhcp_or_homekit(hass, source, data):
|
||||
mocked_bulb = _mocked_bulb()
|
||||
with patch(f"{MODULE_CONFIG_FLOW}.yeelight.Bulb", return_value=mocked_bulb):
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN,
|
||||
context={"source": source},
|
||||
data=data,
|
||||
DOMAIN, context={"source": source}, data=data
|
||||
)
|
||||
assert result["type"] == RESULT_TYPE_FORM
|
||||
assert result["errors"] is None
|
||||
|
||||
with patch(f"{MODULE}.async_setup", return_value=True) as mock_async_setup, patch(
|
||||
f"{MODULE}.async_setup_entry",
|
||||
return_value=True,
|
||||
f"{MODULE}.async_setup_entry", return_value=True
|
||||
) as mock_async_setup_entry:
|
||||
result2 = await hass.config_entries.flow.async_configure(result["flow_id"], {})
|
||||
assert result2["type"] == "create_entry"
|
||||
@ -393,9 +373,7 @@ async def test_discovered_by_dhcp_or_homekit_failed_to_get_id(hass, source, data
|
||||
type(mocked_bulb).get_capabilities = MagicMock(return_value=None)
|
||||
with patch(f"{MODULE_CONFIG_FLOW}.yeelight.Bulb", return_value=mocked_bulb):
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN,
|
||||
context={"source": source},
|
||||
data=data,
|
||||
DOMAIN, context={"source": source}, data=data
|
||||
)
|
||||
assert result["type"] == RESULT_TYPE_ABORT
|
||||
assert result["reason"] == "cannot_connect"
|
||||
|
@ -45,12 +45,7 @@ from tests.common import MockConfigEntry
|
||||
async def test_ip_changes_fallback_discovery(hass: HomeAssistant):
|
||||
"""Test Yeelight ip changes and we fallback to discovery."""
|
||||
config_entry = MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
data={
|
||||
CONF_ID: ID,
|
||||
CONF_HOST: "5.5.5.5",
|
||||
},
|
||||
unique_id=ID,
|
||||
domain=DOMAIN, data={CONF_ID: ID, CONF_HOST: "5.5.5.5"}, unique_id=ID
|
||||
)
|
||||
config_entry.add_to_hass(hass)
|
||||
|
||||
@ -60,12 +55,7 @@ async def test_ip_changes_fallback_discovery(hass: HomeAssistant):
|
||||
side_effect=[OSError, CAPABILITIES, CAPABILITIES]
|
||||
)
|
||||
|
||||
_discovered_devices = [
|
||||
{
|
||||
"capabilities": CAPABILITIES,
|
||||
"ip": IP_ADDRESS,
|
||||
}
|
||||
]
|
||||
_discovered_devices = [{"capabilities": CAPABILITIES, "ip": IP_ADDRESS}]
|
||||
with patch(f"{MODULE}.Bulb", return_value=mocked_bulb), patch(
|
||||
f"{MODULE}.discover_bulbs", return_value=_discovered_devices
|
||||
):
|
||||
@ -92,12 +82,7 @@ async def test_ip_changes_fallback_discovery(hass: HomeAssistant):
|
||||
|
||||
async def test_ip_changes_id_missing_cannot_fallback(hass: HomeAssistant):
|
||||
"""Test Yeelight ip changes and we fallback to discovery."""
|
||||
config_entry = MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
data={
|
||||
CONF_HOST: "5.5.5.5",
|
||||
},
|
||||
)
|
||||
config_entry = MockConfigEntry(domain=DOMAIN, data={CONF_HOST: "5.5.5.5"})
|
||||
config_entry.add_to_hass(hass)
|
||||
|
||||
mocked_bulb = _mocked_bulb(True)
|
||||
@ -170,10 +155,7 @@ async def test_unique_ids_device(hass: HomeAssistant):
|
||||
"""Test Yeelight unique IDs from yeelight device IDs."""
|
||||
config_entry = MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
data={
|
||||
**CONFIG_ENTRY_DATA,
|
||||
CONF_NIGHTLIGHT_SWITCH: True,
|
||||
},
|
||||
data={**CONFIG_ENTRY_DATA, CONF_NIGHTLIGHT_SWITCH: True},
|
||||
unique_id=ID,
|
||||
)
|
||||
config_entry.add_to_hass(hass)
|
||||
@ -197,11 +179,7 @@ async def test_unique_ids_device(hass: HomeAssistant):
|
||||
async def test_unique_ids_entry(hass: HomeAssistant):
|
||||
"""Test Yeelight unique IDs from entry IDs."""
|
||||
config_entry = MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
data={
|
||||
**CONFIG_ENTRY_DATA,
|
||||
CONF_NIGHTLIGHT_SWITCH: True,
|
||||
},
|
||||
domain=DOMAIN, data={**CONFIG_ENTRY_DATA, CONF_NIGHTLIGHT_SWITCH: True}
|
||||
)
|
||||
config_entry.add_to_hass(hass)
|
||||
|
||||
@ -231,12 +209,7 @@ async def test_unique_ids_entry(hass: HomeAssistant):
|
||||
async def test_bulb_off_while_adding_in_ha(hass: HomeAssistant):
|
||||
"""Test Yeelight off while adding to ha, for example on HA start."""
|
||||
config_entry = MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
data={
|
||||
**CONFIG_ENTRY_DATA,
|
||||
CONF_HOST: IP_ADDRESS,
|
||||
},
|
||||
unique_id=ID,
|
||||
domain=DOMAIN, data={**CONFIG_ENTRY_DATA, CONF_HOST: IP_ADDRESS}, unique_id=ID
|
||||
)
|
||||
config_entry.add_to_hass(hass)
|
||||
|
||||
|
@ -353,11 +353,7 @@ async def test_device_types(hass: HomeAssistant):
|
||||
entity_id=ENTITY_LIGHT,
|
||||
):
|
||||
config_entry = MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
data={
|
||||
**CONFIG_ENTRY_DATA,
|
||||
CONF_NIGHTLIGHT_SWITCH: False,
|
||||
},
|
||||
domain=DOMAIN, data={**CONFIG_ENTRY_DATA, CONF_NIGHTLIGHT_SWITCH: False}
|
||||
)
|
||||
config_entry.add_to_hass(hass)
|
||||
|
||||
@ -383,11 +379,7 @@ async def test_device_types(hass: HomeAssistant):
|
||||
if nightlight_properties is None:
|
||||
return
|
||||
config_entry = MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
data={
|
||||
**CONFIG_ENTRY_DATA,
|
||||
CONF_NIGHTLIGHT_SWITCH: True,
|
||||
},
|
||||
domain=DOMAIN, data={**CONFIG_ENTRY_DATA, CONF_NIGHTLIGHT_SWITCH: True}
|
||||
)
|
||||
config_entry.add_to_hass(hass)
|
||||
await _async_setup(config_entry)
|
||||
@ -577,16 +569,13 @@ async def test_effects(hass: HomeAssistant):
|
||||
{YEELIGHT_SLEEP_TRANSACTION: [800]},
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
config_entry = MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
data=CONFIG_ENTRY_DATA,
|
||||
)
|
||||
config_entry = MockConfigEntry(domain=DOMAIN, data=CONFIG_ENTRY_DATA)
|
||||
config_entry.add_to_hass(hass)
|
||||
|
||||
mocked_bulb = _mocked_bulb()
|
||||
|
Loading…
x
Reference in New Issue
Block a user