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:
Daniel Rheinbay 2021-06-01 09:04:49 +02:00 committed by GitHub
parent 549b0b0727
commit 3c452f8c9b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 46 additions and 152 deletions

View File

@ -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)

View File

@ -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,
}
),

View File

@ -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

View File

@ -74,9 +74,7 @@ YAML_CONFIGURATION = {
}
}
CONFIG_ENTRY_DATA = {
CONF_ID: ID,
}
CONFIG_ENTRY_DATA = {CONF_ID: ID}
def _mocked_bulb(cannot_connect=False):

View File

@ -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"

View File

@ -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)

View File

@ -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()