Skip to content
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

Address ruckus_unleashed late review #99411

Merged
merged 11 commits into from
Sep 10, 2023
2 changes: 1 addition & 1 deletion homeassistant/components/ruckus_unleashed/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
if unload_ok:
for listener in hass.data[DOMAIN][entry.entry_id][UNDO_UPDATE_LISTENERS]:
listener()
await hass.data[DOMAIN][entry.entry_id][COORDINATOR].ruckus.close()
await hass.data[DOMAIN][entry.entry_id][COORDINATOR].ruckus.close()
hass.data[DOMAIN].pop(entry.entry_id)

return unload_ok
62 changes: 48 additions & 14 deletions homeassistant/components/ruckus_unleashed/config_flow.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
"""Config flow for Ruckus Unleashed integration."""
from collections.abc import Mapping
import logging
from typing import Any

from aioruckus import AjaxSession, SystemStat
Expand All @@ -19,6 +20,8 @@
KEY_SYS_TITLE,
)

_LOGGER = logging.getLogger(__package__)

DATA_SCHEMA = vol.Schema(
{
vol.Required(CONF_HOST): str,
Expand All @@ -38,26 +41,28 @@ async def validate_input(hass: core.HomeAssistant, data):
async with AjaxSession.async_create(
data[CONF_HOST], data[CONF_USERNAME], data[CONF_PASSWORD]
) as ruckus:
system_info = await ruckus.api.get_system_info(
SystemStat.SYSINFO,
)
mesh_name = (await ruckus.api.get_mesh_info())[API_MESH_NAME]
system_info = await ruckus.api.get_system_info(SystemStat.SYSINFO)
zd_serial = system_info[API_SYS_SYSINFO][API_SYS_SYSINFO_SERIAL]
MartinHjelmare marked this conversation as resolved.
Show resolved Hide resolved
return {
KEY_SYS_TITLE: mesh_name,
KEY_SYS_SERIAL: zd_serial,
}
mesh_info = await ruckus.api.get_mesh_info()
mesh_name = mesh_info[API_MESH_NAME]
except AuthenticationError as autherr:
raise InvalidAuth from autherr
except (ConnectionRefusedError, ConnectionError, KeyError) as connerr:
raise CannotConnect from connerr

return {
KEY_SYS_TITLE: mesh_name,
KEY_SYS_SERIAL: zd_serial,
}


class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
"""Handle a config flow for Ruckus Unleashed."""

VERSION = 1

_reauth_entry: config_entries.ConfigEntry | None = None

async def async_step_user(
self, user_input: dict[str, Any] | None = None
) -> FlowResult:
Expand All @@ -70,6 +75,8 @@ async def async_step_user(
errors["base"] = "cannot_connect"
except InvalidAuth:
errors["base"] = "invalid_auth"
except Exception: # pylint: disable=broad-except
_LOGGER.exception("Unexpected exception")
MartinHjelmare marked this conversation as resolved.
Show resolved Hide resolved
else:
await self.async_set_unique_id(info[KEY_SYS_SERIAL])
self._abort_if_unique_id_configured()
Expand All @@ -83,18 +90,45 @@ async def async_step_user(

async def async_step_reauth(self, entry_data: Mapping[str, Any]) -> FlowResult:
"""Perform reauth upon an API authentication error."""
self._reauth_entry = self.hass.config_entries.async_get_entry(
self.context["entry_id"]
)
return await self.async_step_reauth_confirm()

async def async_step_reauth_confirm(
self, user_input: dict[str, Any] | None = None
) -> FlowResult:
"""Dialog that informs the user that reauth is required."""
if user_input is None:
return self.async_show_form(
step_id="reauth_confirm",
data_schema=DATA_SCHEMA,
)
return await self.async_step_user()
assert self._reauth_entry
errors = {}
if user_input is not None:
MartinHjelmare marked this conversation as resolved.
Show resolved Hide resolved
try:
await validate_input(self.hass, user_input)
except CannotConnect:
errors["base"] = "cannot_connect"
except InvalidAuth:
errors["base"] = "invalid_auth"
except Exception: # pylint: disable=broad-except
_LOGGER.exception("Unexpected exception")
MartinHjelmare marked this conversation as resolved.
Show resolved Hide resolved
else:
self.hass.config_entries.async_update_entry(
self._reauth_entry, data=user_input
)
self.hass.async_create_task(
self.hass.config_entries.async_reload(self._reauth_entry.entry_id)
)
return self.async_abort(reason="reauth_successful")

return self.async_show_form(
step_id="reauth_confirm",
data_schema=DATA_SCHEMA,
errors=errors,
description_placeholders={
MartinHjelmare marked this conversation as resolved.
Show resolved Hide resolved
CONF_HOST: self._reauth_entry.data[CONF_HOST],
CONF_USERNAME: self._reauth_entry.data[CONF_USERNAME],
CONF_PASSWORD: self._reauth_entry.data[CONF_PASSWORD],
},
)


class CannotConnect(exceptions.HomeAssistantError):
Expand Down
3 changes: 2 additions & 1 deletion homeassistant/components/ruckus_unleashed/coordinator.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from aioruckus.exceptions import AuthenticationError

from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ConfigEntryAuthFailed
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed

from .const import API_CLIENT_MAC, DOMAIN, KEY_SYS_CLIENTS, SCAN_INTERVAL
Expand Down Expand Up @@ -40,6 +41,6 @@ async def _async_update_data(self) -> dict:
try:
return {KEY_SYS_CLIENTS: await self._fetch_clients()}
except AuthenticationError as autherror:
raise UpdateFailed(autherror) from autherror
raise ConfigEntryAuthFailed(autherror) from autherror
except (ConnectionRefusedError, ConnectionError) as conerr:
raise UpdateFailed(conerr) from conerr
18 changes: 7 additions & 11 deletions homeassistant/components/ruckus_unleashed/device_tracker.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,20 +103,16 @@ def mac_address(self) -> str:
@property
def name(self) -> str:
"""Return the name."""
return (
self._name
if not self.is_connected
else self.coordinator.data[KEY_SYS_CLIENTS][self._mac][API_CLIENT_HOSTNAME]
)
if not self.is_connected:
return self._name
return self.coordinator.data[KEY_SYS_CLIENTS][self._mac][API_CLIENT_HOSTNAME]

@property
def ip_address(self) -> str:
def ip_address(self) -> str | None:
"""Return the ip address."""
return (
self.coordinator.data[KEY_SYS_CLIENTS][self._mac][API_CLIENT_IP]
if self.is_connected
else None
)
if not self.is_connected:
return None
return self.coordinator.data[KEY_SYS_CLIENTS][self._mac][API_CLIENT_IP]

@property
def is_connected(self) -> bool:
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/ruckus_unleashed/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": ["aioruckus", "xmltodict"],
"requirements": ["aioruckus==0.31", "xmltodict==0.13.0"]
"requirements": ["aioruckus==0.31"]
}
12 changes: 11 additions & 1 deletion homeassistant/components/ruckus_unleashed/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,15 @@
"username": "[%key:common::config_flow::data::username%]",
"password": "[%key:common::config_flow::data::password%]"
}
},
"reauth_confirm": {
MartinHjelmare marked this conversation as resolved.
Show resolved Hide resolved
"title": "[%key:common::config_flow::title::reauth%]",
"description": "The Ruckus Unleashed integration needs to re-authenticate your connection details",
"data": {
"host": "[%key:common::config_flow::data::host%]",
"username": "[%key:common::config_flow::data::username%]",
"password": "[%key:common::config_flow::data::password%]"
}
}
},
"error": {
Expand All @@ -15,7 +24,8 @@
"unknown": "[%key:common::config_flow::error::unknown%]"
},
"abort": {
"already_configured": "[%key:common::config_flow::abort::already_configured_device%]"
"already_configured": "[%key:common::config_flow::abort::already_configured_device%]",
"reauth_successful": "[%key:common::config_flow::abort::reauth_successful%]"
}
}
}
1 change: 0 additions & 1 deletion requirements_all.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2719,7 +2719,6 @@ xknxproject==3.2.0
# homeassistant.components.bluesound
# homeassistant.components.fritz
# homeassistant.components.rest
# homeassistant.components.ruckus_unleashed
# homeassistant.components.startca
# homeassistant.components.ted5000
# homeassistant.components.zestimate
Expand Down
1 change: 0 additions & 1 deletion requirements_test_all.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2001,7 +2001,6 @@ xknxproject==3.2.0
# homeassistant.components.bluesound
# homeassistant.components.fritz
# homeassistant.components.rest
# homeassistant.components.ruckus_unleashed
# homeassistant.components.startca
# homeassistant.components.ted5000
# homeassistant.components.zestimate
Expand Down