Add DHCP discovery to Tailwind (#105981)

This commit is contained in:
Franck Nijhof 2023-12-18 15:52:48 +01:00 committed by GitHub
parent 72fe30439e
commit 5f2a13fec6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 73 additions and 1 deletions

View file

@ -15,6 +15,7 @@ from gotailwind import (
import voluptuous as vol import voluptuous as vol
from homeassistant.components import zeroconf from homeassistant.components import zeroconf
from homeassistant.components.dhcp import DhcpServiceInfo
from homeassistant.config_entries import ConfigEntry, ConfigFlow from homeassistant.config_entries import ConfigEntry, ConfigFlow
from homeassistant.const import CONF_HOST, CONF_TOKEN from homeassistant.const import CONF_HOST, CONF_TOKEN
from homeassistant.data_entry_flow import AbortFlow, FlowResult from homeassistant.data_entry_flow import AbortFlow, FlowResult
@ -182,6 +183,19 @@ class TailwindFlowHandler(ConfigFlow, domain=DOMAIN):
errors=errors, errors=errors,
) )
async def async_step_dhcp(self, discovery_info: DhcpServiceInfo) -> FlowResult:
"""Handle dhcp discovery to update existing entries.
This flow is triggered only by DHCP discovery of known devices.
"""
await self.async_set_unique_id(format_mac(discovery_info.macaddress))
self._abort_if_unique_id_configured(updates={CONF_HOST: discovery_info.ip})
# This situation should never happen, as Home Assistant will only
# send updates for existing entries. In case it does, we'll just
# abort the flow with an unknown error.
return self.async_abort(reason="unknown")
async def _async_step_create_entry(self, *, host: str, token: str) -> FlowResult: async def _async_step_create_entry(self, *, host: str, token: str) -> FlowResult:
"""Create entry.""" """Create entry."""
tailwind = Tailwind( tailwind = Tailwind(

View file

@ -3,6 +3,11 @@
"name": "Tailwind", "name": "Tailwind",
"codeowners": ["@frenck"], "codeowners": ["@frenck"],
"config_flow": true, "config_flow": true,
"dhcp": [
{
"registered_devices": true
}
],
"documentation": "https://www.home-assistant.io/integrations/tailwind", "documentation": "https://www.home-assistant.io/integrations/tailwind",
"integration_type": "device", "integration_type": "device",
"iot_class": "local_polling", "iot_class": "local_polling",

View file

@ -41,6 +41,7 @@
"cannot_connect": "[%key:common::config_flow::error::cannot_connect%]", "cannot_connect": "[%key:common::config_flow::error::cannot_connect%]",
"no_device_id": "The discovered Tailwind device did not provide a device ID.", "no_device_id": "The discovered Tailwind device did not provide a device ID.",
"reauth_successful": "[%key:common::config_flow::abort::reauth_successful%]", "reauth_successful": "[%key:common::config_flow::abort::reauth_successful%]",
"unknown": "[%key:common::config_flow::error::unknown%]",
"unsupported_firmware": "The firmware of your Tailwind device is not supported. Please update your Tailwind device to the latest firmware version using the Tailwind app." "unsupported_firmware": "The firmware of your Tailwind device is not supported. Please update your Tailwind device to the latest firmware version using the Tailwind app."
} }
}, },

View file

@ -571,6 +571,10 @@ DHCP: list[dict[str, str | bool]] = [
"domain": "tado", "domain": "tado",
"hostname": "tado*", "hostname": "tado*",
}, },
{
"domain": "tailwind",
"registered_devices": True,
},
{ {
"domain": "tesla_wall_connector", "domain": "tesla_wall_connector",
"hostname": "teslawallconnector_*", "hostname": "teslawallconnector_*",

View file

@ -11,8 +11,14 @@ import pytest
from syrupy.assertion import SnapshotAssertion from syrupy.assertion import SnapshotAssertion
from homeassistant.components import zeroconf from homeassistant.components import zeroconf
from homeassistant.components.dhcp import DhcpServiceInfo
from homeassistant.components.tailwind.const import DOMAIN from homeassistant.components.tailwind.const import DOMAIN
from homeassistant.config_entries import SOURCE_REAUTH, SOURCE_USER, SOURCE_ZEROCONF from homeassistant.config_entries import (
SOURCE_DHCP,
SOURCE_REAUTH,
SOURCE_USER,
SOURCE_ZEROCONF,
)
from homeassistant.const import CONF_HOST, CONF_TOKEN from homeassistant.const import CONF_HOST, CONF_TOKEN
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.data_entry_flow import FlowResultType from homeassistant.data_entry_flow import FlowResultType
@ -378,3 +384,45 @@ async def test_reauth_flow_errors(
assert result3.get("type") == FlowResultType.ABORT assert result3.get("type") == FlowResultType.ABORT
assert result3.get("reason") == "reauth_successful" assert result3.get("reason") == "reauth_successful"
async def test_dhcp_discovery_updates_entry(
hass: HomeAssistant,
mock_config_entry: MockConfigEntry,
) -> None:
"""Test DHCP discovery updates config entries."""
mock_config_entry.add_to_hass(hass)
assert mock_config_entry.data[CONF_HOST] == "127.0.0.127"
result = await hass.config_entries.flow.async_init(
DOMAIN,
context={"source": SOURCE_DHCP},
data=DhcpServiceInfo(
hostname="tailwind-3ce90e6d2184.local.",
ip="127.0.0.1",
macaddress="3c:e9:0e:6d:21:84",
),
)
assert result.get("type") == FlowResultType.ABORT
assert result.get("reason") == "already_configured"
assert mock_config_entry.data[CONF_HOST] == "127.0.0.1"
async def test_dhcp_discovery_ignores_unknown(hass: HomeAssistant) -> None:
"""Test DHCP discovery is only used for updates.
Anything else will just abort the flow.
"""
result = await hass.config_entries.flow.async_init(
DOMAIN,
context={"source": SOURCE_DHCP},
data=DhcpServiceInfo(
hostname="tailwind-3ce90e6d2184.local.",
ip="127.0.0.1",
macaddress="3c:e9:0e:6d:21:84",
),
)
assert result.get("type") == FlowResultType.ABORT
assert result.get("reason") == "unknown"