Skip to content

[pull] dev from home-assistant:dev #764

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Jun 4, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 51 additions & 0 deletions homeassistant/components/homee/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,3 +83,54 @@ async def async_step_user(
data_schema=AUTH_SCHEMA,
errors=errors,
)

async def async_step_reconfigure(
self, user_input: dict[str, Any] | None = None
) -> ConfigFlowResult:
"""Handle the reconfigure flow."""
errors: dict[str, str] = {}
reconfigure_entry = self._get_reconfigure_entry()

if user_input:
self.homee = Homee(
user_input[CONF_HOST],
reconfigure_entry.data[CONF_USERNAME],
reconfigure_entry.data[CONF_PASSWORD],
)

try:
await self.homee.get_access_token()
except HomeeConnectionFailedException:
errors["base"] = "cannot_connect"
except HomeeAuthenticationFailedException:
errors["base"] = "invalid_auth"
except Exception:
_LOGGER.exception("Unexpected exception")
errors["base"] = "unknown"
else:
self.hass.loop.create_task(self.homee.run())
await self.homee.wait_until_connected()
self.homee.disconnect()
await self.homee.wait_until_disconnected()

await self.async_set_unique_id(self.homee.settings.uid)
self._abort_if_unique_id_mismatch(reason="wrong_hub")

_LOGGER.debug("Updated homee entry with ID %s", self.homee.settings.uid)
return self.async_update_reload_and_abort(
self._get_reconfigure_entry(), data_updates=user_input
)

return self.async_show_form(
data_schema=vol.Schema(
{
vol.Required(
CONF_HOST, default=reconfigure_entry.data[CONF_HOST]
): str
}
),
description_placeholders={
"name": reconfigure_entry.runtime_data.settings.uid
},
errors=errors,
)
14 changes: 13 additions & 1 deletion homeassistant/components/homee/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
"config": {
"flow_title": "homee {name} ({host})",
"abort": {
"already_configured": "[%key:common::config_flow::abort::already_configured_device%]"
"already_configured": "[%key:common::config_flow::abort::already_configured_device%]",
"reconfigure_successful": "[%key:common::config_flow::abort::reconfigure_successful%]",
"wrong_hub": "Address belongs to a different homee."
},
"error": {
"cannot_connect": "[%key:common::config_flow::error::cannot_connect%]",
Expand All @@ -22,6 +24,16 @@
"username": "The username for your homee.",
"password": "The password for your homee."
}
},
"reconfigure": {
"title": "Reconfigure homee {name}",
"description": "Reconfigure the IP address of your homee.",
"data": {
"host": "[%key:common::config_flow::data::host%]"
},
"data_description": {
"host": "The IP address of your homee."
}
}
}
},
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/immich/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,5 @@
"iot_class": "local_polling",
"loggers": ["aioimmich"],
"quality_scale": "silver",
"requirements": ["aioimmich==0.8.0"]
"requirements": ["aioimmich==0.9.0"]
}
2 changes: 1 addition & 1 deletion homeassistant/components/iskra/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@
"integration_type": "hub",
"iot_class": "local_polling",
"loggers": ["pyiskra"],
"requirements": ["pyiskra==0.1.19"]
"requirements": ["pyiskra==0.1.21"]
}
2 changes: 1 addition & 1 deletion homeassistant/package_constraints.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ aiodns==3.4.0
aiohasupervisor==0.3.1
aiohttp-asyncmdnsresolver==0.1.1
aiohttp-fast-zlib==0.2.3
aiohttp==3.12.7
aiohttp==3.12.8
aiohttp_cors==0.8.1
aiousbwatcher==1.1.1
aiozoneinfo==0.2.3
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ dependencies = [
# change behavior based on presence of supervisor. Deprecated with #127228
# Lib can be removed with 2025.11
"aiohasupervisor==0.3.1",
"aiohttp==3.12.7",
"aiohttp==3.12.8",
"aiohttp_cors==0.8.1",
"aiohttp-fast-zlib==0.2.3",
"aiohttp-asyncmdnsresolver==0.1.1",
Expand Down
2 changes: 1 addition & 1 deletion requirements.txt

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions requirements_all.txt

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions requirements_test_all.txt

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions tests/components/homee/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

HOMEE_ID = "00055511EECC"
HOMEE_IP = "192.168.1.11"
NEW_HOMEE_IP = "192.168.1.12"
HOMEE_NAME = "TestHomee"
TESTUSER = "testuser"
TESTPASS = "testpass"
Expand Down
125 changes: 124 additions & 1 deletion tests/components/homee/test_config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
from homeassistant.core import HomeAssistant
from homeassistant.data_entry_flow import FlowResultType

from .conftest import HOMEE_ID, HOMEE_IP, HOMEE_NAME, TESTPASS, TESTUSER
from .conftest import HOMEE_ID, HOMEE_IP, HOMEE_NAME, NEW_HOMEE_IP, TESTPASS, TESTUSER

from tests.common import MockConfigEntry

Expand Down Expand Up @@ -130,3 +130,126 @@ async def test_flow_already_configured(
)
assert result["type"] is FlowResultType.ABORT
assert result["reason"] == "already_configured"


@pytest.mark.usefixtures("mock_setup_entry")
async def test_reconfigure_success(
hass: HomeAssistant,
mock_config_entry: MockConfigEntry,
mock_homee: AsyncMock,
) -> None:
"""Test the reconfigure flow."""
mock_config_entry.add_to_hass(hass)
mock_config_entry.runtime_data = mock_homee
result = await mock_config_entry.start_reconfigure_flow(hass)

assert result["step_id"] == "reconfigure"
assert result["type"] is FlowResultType.FORM
assert result["errors"] == {}
assert result["handler"] == DOMAIN

result2 = await hass.config_entries.flow.async_configure(
result["flow_id"],
user_input={
CONF_HOST: NEW_HOMEE_IP,
},
)

assert result2["type"] is FlowResultType.ABORT
assert result2["reason"] == "reconfigure_successful"

# Confirm that the config entry has been updated
assert mock_config_entry.data[CONF_HOST] == NEW_HOMEE_IP
assert mock_config_entry.data[CONF_USERNAME] == TESTUSER
assert mock_config_entry.data[CONF_PASSWORD] == TESTPASS


@pytest.mark.parametrize(
("side_eff", "error"),
[
(
HomeeConnectionFailedException("connection timed out"),
{"base": "cannot_connect"},
),
(
HomeeAuthFailedException("wrong username or password"),
{"base": "invalid_auth"},
),
(
Exception,
{"base": "unknown"},
),
],
)
async def test_reconfigure_errors(
hass: HomeAssistant,
mock_config_entry: MockConfigEntry,
mock_homee: AsyncMock,
side_eff: Exception,
error: dict[str, str],
) -> None:
"""Test reconfigure flow errors."""
mock_config_entry.add_to_hass(hass)
mock_config_entry.runtime_data = mock_homee
result = await mock_config_entry.start_reconfigure_flow(hass)

assert result["type"] is FlowResultType.FORM
assert result["step_id"] == "reconfigure"

mock_homee.get_access_token.side_effect = side_eff
result2 = await hass.config_entries.flow.async_configure(
result["flow_id"],
user_input={
CONF_HOST: NEW_HOMEE_IP,
},
)

assert result2["type"] is FlowResultType.FORM
assert result2["errors"] == error

# Confirm that the config entry is unchanged
assert mock_config_entry.data[CONF_HOST] == HOMEE_IP

mock_homee.get_access_token.side_effect = None
result2 = await hass.config_entries.flow.async_configure(
result["flow_id"],
user_input={
CONF_HOST: NEW_HOMEE_IP,
},
)

assert result2["type"] is FlowResultType.ABORT
assert result2["reason"] == "reconfigure_successful"

# Confirm that the config entry has been updated
assert mock_config_entry.data[CONF_HOST] == NEW_HOMEE_IP
assert mock_config_entry.data[CONF_USERNAME] == TESTUSER
assert mock_config_entry.data[CONF_PASSWORD] == TESTPASS


async def test_reconfigure_wrong_uid(
hass: HomeAssistant,
mock_config_entry: MockConfigEntry,
mock_homee: AsyncMock,
) -> None:
"""Test reconfigure flow with wrong UID."""
mock_config_entry.add_to_hass(hass)
mock_homee.settings.uid = "wrong_uid"
mock_config_entry.runtime_data = mock_homee
result = await mock_config_entry.start_reconfigure_flow(hass)

assert result["type"] is FlowResultType.FORM
assert result["step_id"] == "reconfigure"

result2 = await hass.config_entries.flow.async_configure(
result["flow_id"],
user_input={
CONF_HOST: NEW_HOMEE_IP,
},
)

assert result2["type"] is FlowResultType.ABORT
assert result2["reason"] == "wrong_hub"

# Confirm that the config entry is unchanged
assert mock_config_entry.data[CONF_HOST] == HOMEE_IP