mirror of
https://github.com/home-assistant/core.git
synced 2026-09-25 07:51:46 -05:00
Use dhcp discovery to update midea device IP (#180955)
This commit is contained in:
@@ -31,7 +31,9 @@ from homeassistant.const import (
|
||||
CONF_TYPE,
|
||||
)
|
||||
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
||||
from homeassistant.helpers.device_registry import format_mac
|
||||
from homeassistant.helpers.selector import SelectSelector, SelectSelectorConfig
|
||||
from homeassistant.helpers.service_info.dhcp import DhcpServiceInfo
|
||||
|
||||
from .const import (
|
||||
CONF_ACCOUNT,
|
||||
@@ -772,3 +774,29 @@ class MideaConfigFlow(ConfigFlow, domain=DOMAIN):
|
||||
data_schema=schema,
|
||||
errors={"base": error} if error else None,
|
||||
)
|
||||
|
||||
@override
|
||||
async def async_step_dhcp(
|
||||
self, discovery_info: DhcpServiceInfo
|
||||
) -> ConfigFlowResult:
|
||||
"""Handle DHCP discovery of a known Midea device.
|
||||
|
||||
Only devices already configured (matched via ``registered_devices``)
|
||||
reach this step. It is used to keep the stored host in sync with the
|
||||
current IP address of the device.
|
||||
"""
|
||||
mac = format_mac(discovery_info.macaddress)
|
||||
for entry in self._async_current_entries():
|
||||
if (entry_mac := entry.data.get(CONF_MAC)) is None or format_mac(
|
||||
entry_mac
|
||||
) != mac:
|
||||
continue
|
||||
if entry.data[CONF_IP_ADDRESS] != discovery_info.ip:
|
||||
self.hass.config_entries.async_update_entry(
|
||||
entry,
|
||||
data=entry.data | {CONF_IP_ADDRESS: discovery_info.ip},
|
||||
)
|
||||
self.hass.config_entries.async_schedule_reload(entry.entry_id)
|
||||
return self.async_abort(reason="already_configured")
|
||||
|
||||
return self.async_abort(reason="no_devices_found")
|
||||
|
||||
@@ -3,6 +3,11 @@
|
||||
"name": "Midea",
|
||||
"codeowners": ["@chemelli74", "@rokam", "@caibinqing"],
|
||||
"config_flow": true,
|
||||
"dhcp": [
|
||||
{
|
||||
"registered_devices": true
|
||||
}
|
||||
],
|
||||
"documentation": "https://www.home-assistant.io/integrations/midea",
|
||||
"integration_type": "device",
|
||||
"iot_class": "local_polling",
|
||||
|
||||
Generated
+4
@@ -651,6 +651,10 @@ DHCP: Final[list[dict[str, str | bool]]] = [
|
||||
"hostname": "lyric-*",
|
||||
"macaddress": "00D02D*",
|
||||
},
|
||||
{
|
||||
"domain": "midea",
|
||||
"registered_devices": True,
|
||||
},
|
||||
{
|
||||
"domain": "mitsubishi_comfort",
|
||||
"registered_devices": True,
|
||||
|
||||
@@ -7,9 +7,9 @@ from unittest.mock import AsyncMock, patch
|
||||
from midealocal.const import DeviceType
|
||||
import pytest
|
||||
|
||||
from homeassistant.components.midea.const import CONF_KEY, CONF_SUBTYPE, DOMAIN
|
||||
from homeassistant.components.midea.const import CONF_KEY, CONF_SN, CONF_SUBTYPE, DOMAIN
|
||||
from homeassistant.components.midea.device_catalog import MIDEA_DEVICE_NAMES
|
||||
from homeassistant.const import CONF_NAME, CONF_TOKEN, CONF_TYPE
|
||||
from homeassistant.const import CONF_MAC, CONF_NAME, CONF_TOKEN, CONF_TYPE
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import entity_registry as er
|
||||
|
||||
@@ -179,6 +179,8 @@ def mock_config_entry() -> Callable[[DummyDevice], MockConfigEntry]:
|
||||
**BASE_DATA,
|
||||
CONF_TYPE: device.device_type,
|
||||
CONF_NAME: MIDEA_DEVICE_NAMES[device.device_type],
|
||||
CONF_MAC: TEST_MAC_ADDRESS,
|
||||
CONF_SN: TEST_SERIAL_NUMBER,
|
||||
CONF_TOKEN: TEST_TOKEN,
|
||||
CONF_KEY: TEST_KEY,
|
||||
CONF_SUBTYPE: TEST_SUBTYPE,
|
||||
|
||||
@@ -15,6 +15,7 @@ from homeassistant.const import (
|
||||
CONF_TYPE,
|
||||
)
|
||||
|
||||
TEST_HOSTNAME = "net_ac_2233"
|
||||
TEST_DEVICE_ID = 12345678
|
||||
TEST_IP_ADDRESS = "1.1.1.1"
|
||||
TEST_KEY = "bb" * 16
|
||||
|
||||
@@ -17,10 +17,12 @@
|
||||
'device_id': 12345678,
|
||||
'ip_address': '1.1.1.1',
|
||||
'key': '**REDACTED**',
|
||||
'mac': '**REDACTED**',
|
||||
'model': 'MSAGBU-09HRFN8',
|
||||
'name': 'Air Conditioner',
|
||||
'port': 6444,
|
||||
'protocol': 3,
|
||||
'sn': '**REDACTED**',
|
||||
'subtype': 0,
|
||||
'token': '**REDACTED**',
|
||||
'type': 172,
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
"""Tests for the Midea config flow."""
|
||||
|
||||
from collections.abc import Callable
|
||||
from functools import partial
|
||||
from unittest.mock import AsyncMock, MagicMock, patch
|
||||
|
||||
@@ -22,7 +23,7 @@ from homeassistant.components.midea.const import (
|
||||
DOMAIN,
|
||||
)
|
||||
from homeassistant.components.midea.device_catalog import MIDEA_DEVICE_NAMES
|
||||
from homeassistant.config_entries import SOURCE_USER
|
||||
from homeassistant.config_entries import SOURCE_DHCP, SOURCE_USER
|
||||
from homeassistant.const import (
|
||||
CONF_DEVICE,
|
||||
CONF_DEVICE_ID,
|
||||
@@ -33,17 +34,21 @@ from homeassistant.const import (
|
||||
CONF_PASSWORD,
|
||||
CONF_PORT,
|
||||
CONF_PROTOCOL,
|
||||
CONF_SOURCE,
|
||||
CONF_TOKEN,
|
||||
CONF_TYPE,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.data_entry_flow import FlowResultType
|
||||
from homeassistant.helpers.service_info.dhcp import DhcpServiceInfo
|
||||
|
||||
from .conftest import DummyDevice, default_ac_device
|
||||
from .const import (
|
||||
BASE_DATA,
|
||||
DISCOVERY_RESULT,
|
||||
EXTENDED_DATA,
|
||||
TEST_DEVICE_ID,
|
||||
TEST_HOSTNAME,
|
||||
TEST_IP_ADDRESS,
|
||||
TEST_KEY,
|
||||
TEST_MAC_ADDRESS,
|
||||
@@ -2031,3 +2036,79 @@ async def test_auth_method_preset_login_failed(hass: HomeAssistant) -> None:
|
||||
assert result["type"] is FlowResultType.FORM
|
||||
assert result["step_id"] == "auth_method"
|
||||
assert result["errors"] == {"base": "preset_login_failed"}
|
||||
|
||||
|
||||
async def test_dhcp_discovery_updates_host(
|
||||
hass: HomeAssistant,
|
||||
mock_config_entry: Callable[[DummyDevice], MockConfigEntry],
|
||||
) -> None:
|
||||
"""Test DHCP discovery of a known device updates its stored host."""
|
||||
config_entry = mock_config_entry(default_ac_device())
|
||||
config_entry.add_to_hass(hass)
|
||||
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={CONF_SOURCE: SOURCE_DHCP},
|
||||
data=DhcpServiceInfo(
|
||||
hostname=TEST_HOSTNAME,
|
||||
ip="127.0.0.42",
|
||||
macaddress=TEST_MAC_ADDRESS.replace(":", ""),
|
||||
),
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert result["type"] is FlowResultType.ABORT
|
||||
assert result["reason"] == "already_configured"
|
||||
assert config_entry.data[CONF_IP_ADDRESS] == "127.0.0.42"
|
||||
|
||||
|
||||
async def test_dhcp_discovery_same_host(
|
||||
hass: HomeAssistant,
|
||||
mock_config_entry: Callable[[DummyDevice], MockConfigEntry],
|
||||
) -> None:
|
||||
"""Test DHCP discovery does nothing when the host is already up to date."""
|
||||
config_entry = mock_config_entry(default_ac_device())
|
||||
config_entry.add_to_hass(hass)
|
||||
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={CONF_SOURCE: SOURCE_DHCP},
|
||||
data=DhcpServiceInfo(
|
||||
hostname=TEST_HOSTNAME,
|
||||
ip=TEST_IP_ADDRESS,
|
||||
macaddress=TEST_MAC_ADDRESS.replace(":", ""),
|
||||
),
|
||||
)
|
||||
|
||||
assert result["type"] is FlowResultType.ABORT
|
||||
assert result["reason"] == "already_configured"
|
||||
assert config_entry.data[CONF_IP_ADDRESS] == TEST_IP_ADDRESS
|
||||
|
||||
|
||||
async def test_dhcp_discovery_no_match(
|
||||
hass: HomeAssistant,
|
||||
mock_config_entry: Callable[[DummyDevice], MockConfigEntry],
|
||||
) -> None:
|
||||
"""Test DHCP discovery aborts when no matching entry is configured."""
|
||||
config_entry = mock_config_entry(default_ac_device())
|
||||
config_entry.add_to_hass(hass)
|
||||
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={CONF_SOURCE: SOURCE_DHCP},
|
||||
data=DhcpServiceInfo(
|
||||
hostname=TEST_HOSTNAME,
|
||||
ip="1.2.3.4",
|
||||
macaddress="aabbccddeeff",
|
||||
),
|
||||
)
|
||||
|
||||
assert result["type"] is FlowResultType.ABORT
|
||||
assert result["reason"] == "no_devices_found"
|
||||
assert config_entry.data[CONF_IP_ADDRESS] == TEST_IP_ADDRESS
|
||||
|
||||
Reference in New Issue
Block a user