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
4 changes: 2 additions & 2 deletions CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
Expand Up @@ -1057,8 +1057,8 @@ build.json @home-assistant/supervisor
/tests/components/rss_feed_template/ @home-assistant/core
/homeassistant/components/rtsp_to_webrtc/ @allenporter
/tests/components/rtsp_to_webrtc/ @allenporter
/homeassistant/components/ruckus_unleashed/ @gabe565 @lanrat
/tests/components/ruckus_unleashed/ @gabe565 @lanrat
/homeassistant/components/ruckus_unleashed/ @lanrat @ms264556 @gabe565
/tests/components/ruckus_unleashed/ @lanrat @ms264556 @gabe565
/homeassistant/components/ruuvi_gateway/ @akx
/tests/components/ruuvi_gateway/ @akx
/homeassistant/components/ruuvitag_ble/ @akx
Expand Down
18 changes: 10 additions & 8 deletions homeassistant/components/ruckus_unleashed/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import logging

from aioruckus import AjaxSession
from aioruckus.exceptions import AuthenticationError
from aioruckus.exceptions import AuthenticationError, SchemaError

from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_HOST, CONF_PASSWORD, CONF_USERNAME
Expand Down Expand Up @@ -31,16 +31,18 @@
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Set up Ruckus Unleashed from a config entry."""

ruckus = AjaxSession.async_create(
entry.data[CONF_HOST],
entry.data[CONF_USERNAME],
entry.data[CONF_PASSWORD],
)
try:
ruckus = AjaxSession.async_create(
entry.data[CONF_HOST],
entry.data[CONF_USERNAME],
entry.data[CONF_PASSWORD],
)
await ruckus.login()
except (ConnectionRefusedError, ConnectionError) as conerr:
except (ConnectionError, SchemaError) as conerr:
await ruckus.close()
raise ConfigEntryNotReady from conerr
except AuthenticationError as autherr:
await ruckus.close()
raise ConfigEntryAuthFailed from autherr

coordinator = RuckusUnleashedDataUpdateCoordinator(hass, ruckus=ruckus)
Expand Down Expand Up @@ -84,7 +86,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
64 changes: 38 additions & 26 deletions homeassistant/components/ruckus_unleashed/config_flow.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
"""Config flow for Ruckus Unleashed integration."""
from collections.abc import Mapping
import logging
from typing import Any

from aioruckus import AjaxSession, SystemStat
from aioruckus.exceptions import AuthenticationError
from aioruckus.exceptions import AuthenticationError, SchemaError
import voluptuous as vol

from homeassistant import config_entries, core, exceptions
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:
except (ConnectionError, SchemaError) 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,30 +75,37 @@ 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
errors["base"] = "unknown"
else:
await self.async_set_unique_id(info[KEY_SYS_SERIAL])
self._abort_if_unique_id_configured()
return self.async_create_entry(
title=info[KEY_SYS_TITLE], data=user_input
if self._reauth_entry is None:
await self.async_set_unique_id(info[KEY_SYS_SERIAL])
MartinHjelmare marked this conversation as resolved.
Show resolved Hide resolved
self._abort_if_unique_id_configured()
return self.async_create_entry(
title=info[KEY_SYS_TITLE], data=user_input
)

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")

data_schema = self.add_suggested_values_to_schema(
DATA_SCHEMA, self._reauth_entry.data if self._reauth_entry else {}
)
return self.async_show_form(
step_id="user", data_schema=DATA_SCHEMA, errors=errors
step_id="user", data_schema=data_schema, errors=errors
)

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


Expand Down
7 changes: 4 additions & 3 deletions homeassistant/components/ruckus_unleashed/coordinator.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@
import logging

from aioruckus import AjaxSession
from aioruckus.exceptions import AuthenticationError
from aioruckus.exceptions import AuthenticationError, SchemaError

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
except (ConnectionRefusedError, ConnectionError) as conerr:
raise ConfigEntryAuthFailed(autherror) from autherror
except (ConnectionError, SchemaError) 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
4 changes: 2 additions & 2 deletions homeassistant/components/ruckus_unleashed/manifest.json
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
{
"domain": "ruckus_unleashed",
"name": "Ruckus Unleashed",
"codeowners": ["@gabe565", "@lanrat"],
"codeowners": ["@lanrat", "@ms264556", "@gabe565"],
"config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/ruckus_unleashed",
"integration_type": "hub",
"iot_class": "local_polling",
"loggers": ["aioruckus", "xmltodict"],
"requirements": ["aioruckus==0.31", "xmltodict==0.13.0"]
"requirements": ["aioruckus==0.34"]
}
3 changes: 2 additions & 1 deletion homeassistant/components/ruckus_unleashed/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,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%]"
}
}
}
3 changes: 1 addition & 2 deletions requirements_all.txt
Original file line number Diff line number Diff line change
Expand Up @@ -333,7 +333,7 @@ aiorecollect==1.0.8
aioridwell==2023.07.0

# homeassistant.components.ruckus_unleashed
aioruckus==0.31
aioruckus==0.34

# homeassistant.components.ruuvi_gateway
aioruuvigateway==0.1.0
Expand Down Expand Up @@ -2722,7 +2722,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
3 changes: 1 addition & 2 deletions requirements_test_all.txt
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,7 @@ aiorecollect==1.0.8
aioridwell==2023.07.0

# homeassistant.components.ruckus_unleashed
aioruckus==0.31
aioruckus==0.34

# homeassistant.components.ruuvi_gateway
aioruuvigateway==0.1.0
Expand Down Expand Up @@ -2004,7 +2004,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