diff --git a/homeassistant/components/withings/manifest.json b/homeassistant/components/withings/manifest.json index 886eb66f5e0..ad9b9a6fe71 100644 --- a/homeassistant/components/withings/manifest.json +++ b/homeassistant/components/withings/manifest.json @@ -5,6 +5,11 @@ "codeowners": ["@joostlek"], "config_flow": true, "dependencies": ["application_credentials", "http", "webhook"], + "dhcp": [ + { + "macaddress": "0024E4*" + } + ], "documentation": "https://www.home-assistant.io/integrations/withings", "iot_class": "cloud_push", "loggers": ["aiowithings"], diff --git a/homeassistant/generated/dhcp.py b/homeassistant/generated/dhcp.py index 22a09945a80..67531ceced8 100644 --- a/homeassistant/generated/dhcp.py +++ b/homeassistant/generated/dhcp.py @@ -1119,6 +1119,10 @@ DHCP: Final[list[dict[str, str | bool]]] = [ "domain": "vicare", "macaddress": "B87424*", }, + { + "domain": "withings", + "macaddress": "0024E4*", + }, { "domain": "wiz", "registered_devices": True, diff --git a/tests/components/withings/test_config_flow.py b/tests/components/withings/test_config_flow.py index 39c8340a78e..d0ad5b2659a 100644 --- a/tests/components/withings/test_config_flow.py +++ b/tests/components/withings/test_config_flow.py @@ -4,8 +4,9 @@ from unittest.mock import AsyncMock, patch import pytest +from homeassistant.components.dhcp import DhcpServiceInfo from homeassistant.components.withings.const import DOMAIN -from homeassistant.config_entries import SOURCE_USER +from homeassistant.config_entries import SOURCE_DHCP, SOURCE_USER from homeassistant.core import HomeAssistant from homeassistant.data_entry_flow import FlowResultType from homeassistant.helpers import config_entry_oauth2_flow @@ -293,3 +294,65 @@ async def test_config_flow_with_invalid_credentials( assert result assert result["type"] is FlowResultType.ABORT assert result["reason"] == "oauth_error" + + +@pytest.mark.usefixtures("current_request_with_host") +async def test_dhcp( + hass: HomeAssistant, + hass_client_no_auth: ClientSessionGenerator, + aioclient_mock: AiohttpClientMocker, +) -> None: + """Check DHCP discovery.""" + + service_info = DhcpServiceInfo( + hostname="device", + ip="192.168.0.1", + macaddress="0024e4bd30de", + ) + result = await hass.config_entries.flow.async_init( + DOMAIN, context={"source": SOURCE_DHCP}, data=service_info + ) + state = config_entry_oauth2_flow._encode_jwt( + hass, + { + "flow_id": result["flow_id"], + "redirect_uri": "https://example.com/auth/external/callback", + }, + ) + + assert result["type"] is FlowResultType.EXTERNAL_STEP + assert result["url"] == ( + "https://account.withings.com/oauth2_user/authorize2?" + f"response_type=code&client_id={CLIENT_ID}&" + "redirect_uri=https://example.com/auth/external/callback&" + f"state={state}" + "&scope=user.info,user.metrics,user.activity,user.sleepevents" + ) + + client = await hass_client_no_auth() + resp = await client.get(f"/auth/external/callback?code=abcd&state={state}") + assert resp.status == 200 + assert resp.headers["content-type"] == "text/html; charset=utf-8" + + aioclient_mock.clear_requests() + aioclient_mock.post( + "https://wbsapi.withings.net/v2/oauth2", + json={ + "body": { + "refresh_token": "mock-refresh-token", + "access_token": "mock-access-token", + "type": "Bearer", + "expires_in": 60, + "userid": 600, + }, + }, + ) + with patch( + "homeassistant.components.withings.async_setup_entry", return_value=True + ) as mock_setup: + result = await hass.config_entries.flow.async_configure(result["flow_id"]) + + assert len(hass.config_entries.async_entries(DOMAIN)) == 1 + assert len(mock_setup.mock_calls) == 1 + + assert result["type"] is FlowResultType.CREATE_ENTRY