1
0
mirror of https://github.com/home-assistant/core.git synced 2026-07-01 19:57:08 +01:00

Support Yardian YC models (#172347)

Co-authored-by: Joostlek <joostlek@outlook.com>
This commit is contained in:
Yardian Support
2026-06-02 02:40:05 +08:00
committed by GitHub
parent d7219aa025
commit be2aaf926b
4 changed files with 58 additions and 161 deletions
+6 -1
View File
@@ -21,7 +21,12 @@ async def async_setup_entry(hass: HomeAssistant, entry: YardianConfigEntry) -> b
host = entry.data[CONF_HOST]
access_token = entry.data[CONF_ACCESS_TOKEN]
controller = AsyncYardianClient(async_get_clientsession(hass), host, access_token)
# Change this line to use .create()
# This ensures the coordinator's controller knows if it is YP or YC
controller = await AsyncYardianClient.create(
async_get_clientsession(hass), host, token=access_token
)
coordinator = YardianUpdateCoordinator(hass, entry, controller)
await coordinator.async_config_entry_first_refresh()
@@ -34,10 +34,10 @@ class YardianConfigFlow(ConfigFlow, domain=DOMAIN):
async def async_fetch_device_info(self, host: str, access_token: str) -> DeviceInfo:
"""Fetch device info from Yardian."""
yarcli = AsyncYardianClient(
yarcli = await AsyncYardianClient.create(
async_get_clientsession(self.hass),
host,
access_token,
token=access_token,
)
return await yarcli.fetch_device_info()
+9 -4
View File
@@ -32,7 +32,7 @@ def mock_config_entry() -> MockConfigEntry:
CONF_ACCESS_TOKEN: "abc",
CONF_NAME: "Yardian",
"yid": "yid123",
"model": "PRO1902",
"model": "PRO1902C1",
"serialNumber": "SN1",
},
title="Yardian Smart Sprinkler",
@@ -48,12 +48,17 @@ def mock_yardian_client() -> Generator[AsyncMock]:
) as client_cls,
patch(
"homeassistant.components.yardian.config_flow.AsyncYardianClient",
autospec=True,
) as flow_client_cls,
new=client_cls,
),
):
client = client_cls.return_value
flow_client_cls.return_value = client
client_cls.create.return_value = client
client.fetch_device_info.return_value = {
"name": "fake_name",
"yid": "fake_yid",
}
client.fetch_device_state.return_value = YardianDeviceState(
zones=[["Zone 1", 1], ["Zone 2", 0]],
active_zones={0},
+41 -154
View File
@@ -1,189 +1,76 @@
"""Test the Yardian config flow."""
from unittest.mock import AsyncMock, patch
from unittest.mock import AsyncMock
import pytest
from pyyardian import NetworkException, NotAuthorizedException
from homeassistant import config_entries
from homeassistant.components.yardian.const import DOMAIN, PRODUCT_NAME
from homeassistant.config_entries import SOURCE_USER
from homeassistant.core import HomeAssistant
from homeassistant.data_entry_flow import FlowResultType
pytestmark = pytest.mark.usefixtures("mock_setup_entry")
pytestmark = pytest.mark.usefixtures("mock_setup_entry", "mock_yardian_client")
async def test_form(hass: HomeAssistant, mock_setup_entry: AsyncMock) -> None:
async def test_form(hass: HomeAssistant) -> None:
"""Test we get the form."""
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": config_entries.SOURCE_USER}
DOMAIN, context={"source": SOURCE_USER}
)
assert result["type"] is FlowResultType.FORM
assert result["errors"] == {}
with patch(
"homeassistant.components.yardian.config_flow.AsyncYardianClient.fetch_device_info",
return_value={"name": "fake_name", "yid": "fake_yid"},
):
result2 = await hass.config_entries.flow.async_configure(
result["flow_id"],
{
"host": "fake_host",
"access_token": "fake_token",
},
)
await hass.async_block_till_done()
result = await hass.config_entries.flow.async_configure(
result["flow_id"],
{"host": "fake_host", "access_token": "fake_token"},
)
await hass.async_block_till_done()
assert result2["type"] is FlowResultType.CREATE_ENTRY
assert result2["title"] == PRODUCT_NAME
assert result2["data"] == {
assert result["type"] is FlowResultType.CREATE_ENTRY
assert result["title"] == PRODUCT_NAME
assert result["data"] == {
"host": "fake_host",
"access_token": "fake_token",
"name": "fake_name",
"yid": "fake_yid",
}
assert len(mock_setup_entry.mock_calls) == 1
async def test_form_invalid_auth(
hass: HomeAssistant, mock_setup_entry: AsyncMock
@pytest.mark.parametrize(
("exception", "error"),
[
(NotAuthorizedException, "invalid_auth"),
(NetworkException, "cannot_connect"),
(Exception, "unknown"),
],
)
async def test_form_errors(
hass: HomeAssistant,
mock_yardian_client: AsyncMock,
exception: Exception,
error: str,
) -> None:
"""Test we handle invalid auth."""
"""Test we handle errors and recover."""
mock_yardian_client.fetch_device_info.side_effect = exception
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": config_entries.SOURCE_USER}
DOMAIN, context={"source": SOURCE_USER}
)
with patch(
"homeassistant.components.yardian.config_flow.AsyncYardianClient.fetch_device_info",
side_effect=NotAuthorizedException,
):
result2 = await hass.config_entries.flow.async_configure(
result["flow_id"],
{
"host": "fake_host",
"access_token": "fake_token",
},
)
assert result2["type"] is FlowResultType.FORM
assert result2["errors"] == {"base": "invalid_auth"}
# Should be recoverable after hits error
with patch(
"homeassistant.components.yardian.config_flow.AsyncYardianClient.fetch_device_info",
return_value={"name": "fake_name", "yid": "fake_yid"},
):
result3 = await hass.config_entries.flow.async_configure(
result["flow_id"],
{
"host": "fake_host",
"access_token": "fake_token",
},
)
await hass.async_block_till_done()
assert result3["type"] is FlowResultType.CREATE_ENTRY
assert result3["title"] == PRODUCT_NAME
assert result3["data"] == {
"host": "fake_host",
"access_token": "fake_token",
"name": "fake_name",
"yid": "fake_yid",
}
assert len(mock_setup_entry.mock_calls) == 1
async def test_form_cannot_connect(
hass: HomeAssistant, mock_setup_entry: AsyncMock
) -> None:
"""Test we handle cannot connect error."""
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": config_entries.SOURCE_USER}
result = await hass.config_entries.flow.async_configure(
result["flow_id"],
{"host": "fake_host", "access_token": "fake_token"},
)
with patch(
"homeassistant.components.yardian.config_flow.AsyncYardianClient.fetch_device_info",
side_effect=NetworkException,
):
result2 = await hass.config_entries.flow.async_configure(
result["flow_id"],
{
"host": "fake_host",
"access_token": "fake_token",
},
)
assert result["type"] is FlowResultType.FORM
assert result["errors"] == {"base": error}
assert result2["type"] is FlowResultType.FORM
assert result2["errors"] == {"base": "cannot_connect"}
mock_yardian_client.fetch_device_info.side_effect = None
# Should be recoverable after hits error
with patch(
"homeassistant.components.yardian.config_flow.AsyncYardianClient.fetch_device_info",
return_value={"name": "fake_name", "yid": "fake_yid"},
):
result3 = await hass.config_entries.flow.async_configure(
result["flow_id"],
{
"host": "fake_host",
"access_token": "fake_token",
},
)
await hass.async_block_till_done()
assert result3["type"] is FlowResultType.CREATE_ENTRY
assert result3["title"] == PRODUCT_NAME
assert result3["data"] == {
"host": "fake_host",
"access_token": "fake_token",
"name": "fake_name",
"yid": "fake_yid",
}
assert len(mock_setup_entry.mock_calls) == 1
async def test_form_uncategorized_error(
hass: HomeAssistant, mock_setup_entry: AsyncMock
) -> None:
"""Test we handle uncategorized error."""
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": config_entries.SOURCE_USER}
result = await hass.config_entries.flow.async_configure(
result["flow_id"],
{"host": "fake_host", "access_token": "fake_token"},
)
await hass.async_block_till_done()
with patch(
"homeassistant.components.yardian.config_flow.AsyncYardianClient.fetch_device_info",
side_effect=Exception,
):
result2 = await hass.config_entries.flow.async_configure(
result["flow_id"],
{
"host": "fake_host",
"access_token": "fake_token",
},
)
assert result2["type"] is FlowResultType.FORM
assert result2["errors"] == {"base": "unknown"}
# Should be recoverable after hits error
with patch(
"homeassistant.components.yardian.config_flow.AsyncYardianClient.fetch_device_info",
return_value={"name": "fake_name", "yid": "fake_yid"},
):
result3 = await hass.config_entries.flow.async_configure(
result["flow_id"],
{
"host": "fake_host",
"access_token": "fake_token",
},
)
await hass.async_block_till_done()
assert result3["type"] is FlowResultType.CREATE_ENTRY
assert result3["title"] == PRODUCT_NAME
assert result3["data"] == {
"host": "fake_host",
"access_token": "fake_token",
"name": "fake_name",
"yid": "fake_yid",
}
assert len(mock_setup_entry.mock_calls) == 1
assert result["type"] is FlowResultType.CREATE_ENTRY