Skip to content
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
42 changes: 33 additions & 9 deletions custom_components/generac/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,38 @@ def _extract_email_from_cookie(self, cookie_str):
except Exception:
return None

async def async_step_reconfigure(
self, user_input=None
): # pylint: disable=unused-argument
"""Manage the options."""
return await self.async_step_user(user_input)
async def async_step_reconfigure(self, user_input=None):
"""Handle reconfiguration."""
errors = {}
entry = self.hass.config_entries.async_get_entry(self.context["entry_id"])

if user_input is not None:
session_cookie = user_input.get(CONF_SESSION_COOKIE, "")
error = await self._test_credentials(
"",
"",
session_cookie,
)
if error is None:
return self.async_update_reload_and_abort(
entry,
data={**entry.data, **user_input},
reason="Reconfigure Successful",
)
errors["base"] = error

return self.async_show_form(
step_id="reconfigure",
data_schema=vol.Schema(
{
vol.Required(
CONF_SESSION_COOKIE,
default=entry.data.get(CONF_SESSION_COOKIE),
): str,
}
),
errors=errors,
)

async def async_step_user(self, user_input=None):
"""Handle a flow initialized by the user."""
Expand All @@ -71,9 +98,7 @@ async def async_step_user(self, user_input=None):
unique_id = self._extract_email_from_cookie(session_cookie) or "generac"

await self.async_set_unique_id(unique_id)
# We don't want to abort if the unique ID is already configured
# HA does the right thing and will reconfigure the existing entry
# self._abort_if_unique_id_configured()
self._abort_if_unique_id_configured()

return self.async_create_entry(title=unique_id, data=user_input)
else:
Expand Down Expand Up @@ -122,7 +147,6 @@ class GeneracOptionsFlowHandler(config_entries.OptionsFlow):

def __init__(self, config_entry):
"""Initialize HACS options flow."""
self.config_entry = config_entry
self.options = dict(config_entry.options)

async def async_step_init(self, user_input=None): # pylint: disable=unused-argument
Expand Down
2 changes: 1 addition & 1 deletion custom_components/generac/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@
"documentation": "https://github.com/binarydev/ha-generac",
"iot_class": "cloud_polling",
"issue_tracker": "https://github.com/binarydev/ha-generac/issues",
"requirements": ["beautifulsoup4==4.12.2", "dacite==1.8.1"],
"requirements": ["dacite==1.8.1"],
"version": "0.4.0"
}
6 changes: 6 additions & 0 deletions package-lock.json

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

1 change: 0 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
beautifulsoup4==4.13.4
dacite==1.9.2
homeassistant==2025.8.3
voluptuous==0.15.2
Expand Down
60 changes: 55 additions & 5 deletions tests/test_config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -169,19 +169,69 @@ async def test_options_flow(hass: HomeAssistant) -> None:
@pytest.mark.asyncio
async def test_reconfigure_flow(hass: HomeAssistant) -> None:
"""Test the reconfigure flow."""
entry = MockConfigEntry(domain=DOMAIN, data={}, options={})
entry = MockConfigEntry(
domain=DOMAIN, data={"session_cookie": "old_cookie"}, options={}
)
entry.add_to_hass(hass)

await hass.config_entries.async_setup(entry.entry_id)
await hass.async_block_till_done()
with patch("custom_components.generac.async_setup_entry", return_value=True):
await hass.config_entries.async_setup(entry.entry_id)
await hass.async_block_till_done()

result = await hass.config_entries.flow.async_init(
DOMAIN,
context={
"source": config_entries.SOURCE_RECONFIGURE,
"source": "reconfigure",
"entry_id": entry.entry_id,
},
)

assert result["type"] == "form"
assert result["step_id"] == "user"
assert result["step_id"] == "reconfigure"

with patch(
"custom_components.generac.config_flow.GeneracApiClient.async_get_data",
return_value=True,
), patch("custom_components.generac.async_setup_entry", return_value=True), patch(
"custom_components.generac.async_unload_entry", return_value=True
):
result2 = await hass.config_entries.flow.async_configure(
result["flow_id"],
{
"session_cookie": "new_cookie",
},
)
await hass.async_block_till_done()

assert result2["type"] == "abort"
assert result2["reason"] == "Reconfigure Successful"
assert entry.data["session_cookie"] == "new_cookie"


async def test_duplicate_entry(hass: HomeAssistant) -> None:
"""Test duplicate entry is handled."""
entry = MockConfigEntry(
domain=DOMAIN,
unique_id="binarydev@testing.com",
data={"session_cookie": "existing"},
)
entry.add_to_hass(hass)

await setup.async_setup_component(hass, "persistent_notification", {})
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": config_entries.SOURCE_USER}
)

with patch(
"custom_components.generac.config_flow.GeneracApiClient.async_get_data",
return_value=True,
):
result2 = await hass.config_entries.flow.async_configure(
result["flow_id"],
{
"session_cookie": "MobileLinkClientCookie=%7B%0D%0A%20%20%22signInName%22%3A%20%22binarydev%40testing.com%22%0D%0A%7D",
},
)

assert result2["type"] == "abort"
assert result2["reason"] == "already_configured"