Ensure yeelight model is set in the config entry (#55281)
* Ensure yeelight model is set in the config entry - If the model was not set in the config entry the light could be sent commands it could not handle * update tests * fix testpull/55278/head
parent
f6bb5c77a0
commit
089dfad78a
|
@ -196,7 +196,6 @@ async def _async_initialize(
|
|||
entry_data = hass.data[DOMAIN][DATA_CONFIG_ENTRIES][entry.entry_id] = {
|
||||
DATA_PLATFORMS_LOADED: False
|
||||
}
|
||||
entry.async_on_unload(entry.add_update_listener(_async_update_listener))
|
||||
|
||||
@callback
|
||||
def _async_load_platforms():
|
||||
|
@ -212,6 +211,15 @@ async def _async_initialize(
|
|||
await device.async_setup()
|
||||
entry_data[DATA_DEVICE] = device
|
||||
|
||||
if (
|
||||
device.capabilities
|
||||
and entry.options.get(CONF_MODEL) != device.capabilities["model"]
|
||||
):
|
||||
hass.config_entries.async_update_entry(
|
||||
entry, options={**entry.options, CONF_MODEL: device.capabilities["model"]}
|
||||
)
|
||||
|
||||
entry.async_on_unload(entry.add_update_listener(_async_update_listener))
|
||||
entry.async_on_unload(
|
||||
async_dispatcher_connect(
|
||||
hass, DEVICE_INITIALIZED.format(host), _async_load_platforms
|
||||
|
@ -540,7 +548,7 @@ class YeelightDevice:
|
|||
self._config = config
|
||||
self._host = host
|
||||
self._bulb_device = bulb
|
||||
self._capabilities = {}
|
||||
self.capabilities = {}
|
||||
self._device_type = None
|
||||
self._available = False
|
||||
self._initialized = False
|
||||
|
@ -574,12 +582,12 @@ class YeelightDevice:
|
|||
@property
|
||||
def model(self):
|
||||
"""Return configured/autodetected device model."""
|
||||
return self._bulb_device.model or self._capabilities.get("model")
|
||||
return self._bulb_device.model or self.capabilities.get("model")
|
||||
|
||||
@property
|
||||
def fw_version(self):
|
||||
"""Return the firmware version."""
|
||||
return self._capabilities.get("fw_ver")
|
||||
return self.capabilities.get("fw_ver")
|
||||
|
||||
@property
|
||||
def is_nightlight_supported(self) -> bool:
|
||||
|
@ -674,13 +682,13 @@ class YeelightDevice:
|
|||
async def async_setup(self):
|
||||
"""Fetch capabilities and setup name if available."""
|
||||
scanner = YeelightScanner.async_get(self._hass)
|
||||
self._capabilities = await scanner.async_get_capabilities(self._host) or {}
|
||||
self.capabilities = await scanner.async_get_capabilities(self._host) or {}
|
||||
if name := self._config.get(CONF_NAME):
|
||||
# Override default name when name is set in config
|
||||
self._name = name
|
||||
elif self._capabilities:
|
||||
elif self.capabilities:
|
||||
# Generate name from model and id when capabilities is available
|
||||
self._name = _async_unique_name(self._capabilities)
|
||||
self._name = _async_unique_name(self.capabilities)
|
||||
else:
|
||||
self._name = self._host # Default name is host
|
||||
|
||||
|
|
|
@ -96,7 +96,11 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
|||
if user_input is not None:
|
||||
return self.async_create_entry(
|
||||
title=async_format_model_id(self._discovered_model, self.unique_id),
|
||||
data={CONF_ID: self.unique_id, CONF_HOST: self._discovered_ip},
|
||||
data={
|
||||
CONF_ID: self.unique_id,
|
||||
CONF_HOST: self._discovered_ip,
|
||||
CONF_MODEL: self._discovered_model,
|
||||
},
|
||||
)
|
||||
|
||||
self._set_confirm_only()
|
||||
|
@ -129,6 +133,7 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
|||
data={
|
||||
CONF_HOST: user_input[CONF_HOST],
|
||||
CONF_ID: self.unique_id,
|
||||
CONF_MODEL: model,
|
||||
},
|
||||
)
|
||||
|
||||
|
@ -151,7 +156,11 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
|||
host = urlparse(capabilities["location"]).hostname
|
||||
return self.async_create_entry(
|
||||
title=_async_unique_name(capabilities),
|
||||
data={CONF_ID: unique_id, CONF_HOST: host},
|
||||
data={
|
||||
CONF_ID: unique_id,
|
||||
CONF_HOST: host,
|
||||
CONF_MODEL: capabilities["model"],
|
||||
},
|
||||
)
|
||||
|
||||
configured_devices = {
|
||||
|
|
|
@ -19,7 +19,7 @@ from homeassistant.components.yeelight import (
|
|||
DOMAIN,
|
||||
NIGHTLIGHT_SWITCH_TYPE_LIGHT,
|
||||
)
|
||||
from homeassistant.components.yeelight.config_flow import CannotConnect
|
||||
from homeassistant.components.yeelight.config_flow import MODEL_UNKNOWN, CannotConnect
|
||||
from homeassistant.const import CONF_DEVICE, CONF_HOST, CONF_ID, CONF_NAME
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.data_entry_flow import RESULT_TYPE_ABORT, RESULT_TYPE_FORM
|
||||
|
@ -28,6 +28,7 @@ from . import (
|
|||
CAPABILITIES,
|
||||
ID,
|
||||
IP_ADDRESS,
|
||||
MODEL,
|
||||
MODULE,
|
||||
MODULE_CONFIG_FLOW,
|
||||
NAME,
|
||||
|
@ -87,7 +88,7 @@ async def test_discovery(hass: HomeAssistant):
|
|||
)
|
||||
assert result3["type"] == "create_entry"
|
||||
assert result3["title"] == UNIQUE_FRIENDLY_NAME
|
||||
assert result3["data"] == {CONF_ID: ID, CONF_HOST: IP_ADDRESS}
|
||||
assert result3["data"] == {CONF_ID: ID, CONF_HOST: IP_ADDRESS, CONF_MODEL: MODEL}
|
||||
await hass.async_block_till_done()
|
||||
mock_setup.assert_called_once()
|
||||
mock_setup_entry.assert_called_once()
|
||||
|
@ -160,7 +161,11 @@ async def test_discovery_with_existing_device_present(hass: HomeAssistant):
|
|||
)
|
||||
assert result3["type"] == "create_entry"
|
||||
assert result3["title"] == UNIQUE_FRIENDLY_NAME
|
||||
assert result3["data"] == {CONF_ID: ID, CONF_HOST: IP_ADDRESS}
|
||||
assert result3["data"] == {
|
||||
CONF_ID: ID,
|
||||
CONF_HOST: IP_ADDRESS,
|
||||
CONF_MODEL: MODEL,
|
||||
}
|
||||
await hass.async_block_till_done()
|
||||
await hass.async_block_till_done()
|
||||
|
||||
|
@ -300,7 +305,11 @@ async def test_manual(hass: HomeAssistant):
|
|||
await hass.async_block_till_done()
|
||||
assert result4["type"] == "create_entry"
|
||||
assert result4["title"] == "Color 0x15243f"
|
||||
assert result4["data"] == {CONF_HOST: IP_ADDRESS, CONF_ID: "0x000000000015243f"}
|
||||
assert result4["data"] == {
|
||||
CONF_HOST: IP_ADDRESS,
|
||||
CONF_ID: "0x000000000015243f",
|
||||
CONF_MODEL: MODEL,
|
||||
}
|
||||
|
||||
# Duplicate
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
|
@ -333,7 +342,7 @@ async def test_options(hass: HomeAssistant):
|
|||
|
||||
config = {
|
||||
CONF_NAME: NAME,
|
||||
CONF_MODEL: "",
|
||||
CONF_MODEL: MODEL,
|
||||
CONF_TRANSITION: DEFAULT_TRANSITION,
|
||||
CONF_MODE_MUSIC: DEFAULT_MODE_MUSIC,
|
||||
CONF_SAVE_ON_CHANGE: DEFAULT_SAVE_ON_CHANGE,
|
||||
|
@ -383,7 +392,11 @@ async def test_manual_no_capabilities(hass: HomeAssistant):
|
|||
result["flow_id"], {CONF_HOST: IP_ADDRESS}
|
||||
)
|
||||
assert result["type"] == "create_entry"
|
||||
assert result["data"] == {CONF_HOST: IP_ADDRESS, CONF_ID: None}
|
||||
assert result["data"] == {
|
||||
CONF_HOST: IP_ADDRESS,
|
||||
CONF_ID: None,
|
||||
CONF_MODEL: MODEL_UNKNOWN,
|
||||
}
|
||||
|
||||
|
||||
async def test_discovered_by_homekit_and_dhcp(hass):
|
||||
|
@ -480,7 +493,11 @@ async def test_discovered_by_dhcp_or_homekit(hass, source, data):
|
|||
await hass.async_block_till_done()
|
||||
|
||||
assert result2["type"] == "create_entry"
|
||||
assert result2["data"] == {CONF_HOST: IP_ADDRESS, CONF_ID: "0x000000000015243f"}
|
||||
assert result2["data"] == {
|
||||
CONF_HOST: IP_ADDRESS,
|
||||
CONF_ID: "0x000000000015243f",
|
||||
CONF_MODEL: MODEL,
|
||||
}
|
||||
assert mock_async_setup.called
|
||||
assert mock_async_setup_entry.called
|
||||
|
||||
|
@ -540,7 +557,11 @@ async def test_discovered_ssdp(hass):
|
|||
await hass.async_block_till_done()
|
||||
|
||||
assert result2["type"] == "create_entry"
|
||||
assert result2["data"] == {CONF_HOST: IP_ADDRESS, CONF_ID: "0x000000000015243f"}
|
||||
assert result2["data"] == {
|
||||
CONF_HOST: IP_ADDRESS,
|
||||
CONF_ID: "0x000000000015243f",
|
||||
CONF_MODEL: MODEL,
|
||||
}
|
||||
assert mock_async_setup.called
|
||||
assert mock_async_setup_entry.called
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ from unittest.mock import AsyncMock, patch
|
|||
from yeelight import BulbException, BulbType
|
||||
|
||||
from homeassistant.components.yeelight import (
|
||||
CONF_MODEL,
|
||||
CONF_NIGHTLIGHT_SWITCH,
|
||||
CONF_NIGHTLIGHT_SWITCH_TYPE,
|
||||
DATA_CONFIG_ENTRIES,
|
||||
|
@ -35,6 +36,7 @@ from . import (
|
|||
FAIL_TO_BIND_IP,
|
||||
ID,
|
||||
IP_ADDRESS,
|
||||
MODEL,
|
||||
MODULE,
|
||||
SHORT_ID,
|
||||
_mocked_bulb,
|
||||
|
@ -360,6 +362,7 @@ async def test_async_listen_error_late_discovery(hass, caplog):
|
|||
|
||||
assert "Failed to connect to bulb at" not in caplog.text
|
||||
assert config_entry.state is ConfigEntryState.LOADED
|
||||
assert config_entry.options[CONF_MODEL] == MODEL
|
||||
|
||||
|
||||
async def test_async_listen_error_has_host_with_id(hass: HomeAssistant):
|
||||
|
|
Loading…
Reference in New Issue