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
63 changes: 43 additions & 20 deletions homeassistant/components/asuswrt/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
from homeassistant.core import callback
from homeassistant.data_entry_flow import FlowResult
from homeassistant.helpers import config_validation as cv
from homeassistant.helpers.device_registry import format_mac

from .const import (
CONF_DNSMASQ,
Expand All @@ -41,11 +42,13 @@
PROTOCOL_SSH,
PROTOCOL_TELNET,
)
from .router import get_api
from .router import get_api, get_nvram_info

LABEL_MAC = "LABEL_MAC"

RESULT_CONN_ERROR = "cannot_connect"
RESULT_UNKNOWN = "unknown"
RESULT_SUCCESS = "success"
RESULT_UNKNOWN = "unknown"

_LOGGER = logging.getLogger(__name__)

Expand Down Expand Up @@ -107,7 +110,9 @@ def _show_setup_form(
)

@staticmethod
async def _async_check_connection(user_input: dict[str, Any]) -> str:
async def _async_check_connection(
user_input: dict[str, Any]
) -> tuple[str, str | None]:
"""Attempt to connect the AsusWrt router."""

host: str = user_input[CONF_HOST]
Expand All @@ -117,29 +122,37 @@ async def _async_check_connection(user_input: dict[str, Any]) -> str:

except OSError:
_LOGGER.error("Error connecting to the AsusWrt router at %s", host)
return RESULT_CONN_ERROR
return RESULT_CONN_ERROR, None

except Exception: # pylint: disable=broad-except
_LOGGER.exception(
"Unknown error connecting with AsusWrt router at %s", host
)
return RESULT_UNKNOWN
return RESULT_UNKNOWN, None

if not api.is_connected:
_LOGGER.error("Error connecting to the AsusWrt router at %s", host)
return RESULT_CONN_ERROR
return RESULT_CONN_ERROR, None

label_mac = await get_nvram_info(api, LABEL_MAC)
conf_protocol = user_input[CONF_PROTOCOL]
if conf_protocol == PROTOCOL_TELNET:
api.connection.disconnect()
return RESULT_SUCCESS

unique_id = None
if label_mac and "label_mac" in label_mac:
unique_id = format_mac(label_mac["label_mac"])
return RESULT_SUCCESS, unique_id

async def async_step_user(
self, user_input: dict[str, Any] | None = None
) -> FlowResult:
"""Handle a flow initiated by the user."""
if self._async_current_entries():
return self.async_abort(reason="single_instance_allowed")

# if exist one entry without unique ID, we abort config flow
for unique_id in self._async_current_ids():
if unique_id is None:
return self.async_abort(reason="not_unique_id_exist")

if user_input is None:
return self._show_setup_form(user_input)
Expand All @@ -166,17 +179,27 @@ async def async_step_user(
errors["base"] = "invalid_host"

if not errors:
result = await self._async_check_connection(user_input)
if result != RESULT_SUCCESS:
errors["base"] = result

if errors:
return self._show_setup_form(user_input, errors)

return self.async_create_entry(
title=host,
data=user_input,
)
result, unique_id = await self._async_check_connection(user_input)
if result == RESULT_SUCCESS:
if unique_id:
await self.async_set_unique_id(unique_id)
# we allow configure a single instance without unique id
elif self._async_current_entries():
return self.async_abort(reason="invalid_unique_id")
else:
_LOGGER.warning(
"This device do not provide a valid Unique ID."
" Configuration of multiple instance will not be possible"
)

return self.async_create_entry(
title=host,
data=user_input,
)

errors["base"] = result

return self._show_setup_form(user_input, errors)

@staticmethod
@callback
Expand Down
3 changes: 2 additions & 1 deletion homeassistant/components/asuswrt/diagnostics.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
ATTR_CONNECTIONS,
ATTR_IDENTIFIERS,
CONF_PASSWORD,
CONF_UNIQUE_ID,
CONF_USERNAME,
)
from homeassistant.core import HomeAssistant
Expand All @@ -19,7 +20,7 @@
from .const import DATA_ASUSWRT, DOMAIN
from .router import AsusWrtRouter

TO_REDACT = {CONF_PASSWORD, CONF_USERNAME}
TO_REDACT = {CONF_PASSWORD, CONF_UNIQUE_ID, CONF_USERNAME}
TO_REDACT_DEV = {ATTR_CONNECTIONS, ATTR_IDENTIFIERS}


Expand Down
19 changes: 15 additions & 4 deletions homeassistant/components/asuswrt/router.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
)

CONF_REQ_RELOAD = [CONF_DNSMASQ, CONF_INTERFACE, CONF_REQUIRE_IP]
DEFAULT_NAME = "Asuswrt"

KEY_COORDINATOR = "coordinator"
KEY_SENSORS = "sensors"
Expand Down Expand Up @@ -260,10 +261,10 @@ async def setup(self) -> None:
raise ConfigEntryNotReady

# System
model = await _get_nvram_info(self._api, "MODEL")
model = await get_nvram_info(self._api, "MODEL")
if model and "model" in model:
self._model = model["model"]
firmware = await _get_nvram_info(self._api, "FIRMWARE")
firmware = await get_nvram_info(self._api, "FIRMWARE")
if firmware and "firmver" in firmware and "buildno" in firmware:
self._sw_v = f"{firmware['firmver']} (build {firmware['buildno']})"

Expand Down Expand Up @@ -441,7 +442,7 @@ def update_options(self, new_options: dict[str, Any]) -> bool:
def device_info(self) -> DeviceInfo:
"""Return the device information."""
return DeviceInfo(
identifiers={(DOMAIN, "AsusWRT")},
identifiers={(DOMAIN, self.unique_id or "AsusWRT")},
name=self._host,
model=self._model,
manufacturer="Asus",
Expand All @@ -464,6 +465,16 @@ def host(self) -> str:
"""Return router hostname."""
return self._host

@property
def unique_id(self) -> str | None:
"""Return router unique id."""
return self._entry.unique_id

@property
def name(self) -> str:
"""Return router name."""
return self._host if self.unique_id else DEFAULT_NAME

@property
def devices(self) -> dict[str, AsusWrtDevInfo]:
"""Return devices."""
Expand All @@ -475,7 +486,7 @@ def sensors_coordinator(self) -> dict[str, Any]:
return self._sensors_coordinator


async def _get_nvram_info(api: AsusWrt, info_type: str) -> dict[str, Any]:
async def get_nvram_info(api: AsusWrt, info_type: str) -> dict[str, Any]:
"""Get AsusWrt router info from nvram."""
info = {}
try:
Expand Down
8 changes: 5 additions & 3 deletions homeassistant/components/asuswrt/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ class AsusWrtSensorEntityDescription(SensorEntityDescription):
precision: int = 2


DEFAULT_PREFIX = "Asuswrt"
UNIT_DEVICES = "Devices"

CONNECTION_SENSORS: tuple[AsusWrtSensorEntityDescription, ...] = (
Expand Down Expand Up @@ -190,8 +189,11 @@ def __init__(
super().__init__(coordinator)
self.entity_description: AsusWrtSensorEntityDescription = description

self._attr_name = f"{DEFAULT_PREFIX} {description.name}"
self._attr_unique_id = f"{DOMAIN} {self.name}"
self._attr_name = f"{router.name} {description.name}"
if router.unique_id:
self._attr_unique_id = f"{DOMAIN} {router.unique_id} {description.name}"
else:
self._attr_unique_id = f"{DOMAIN} {self.name}"
self._attr_device_info = router.device_info
self._attr_extra_state_attributes = {"hostname": router.host}

Expand Down
3 changes: 2 additions & 1 deletion homeassistant/components/asuswrt/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@
"unknown": "[%key:common::config_flow::error::unknown%]"
},
"abort": {
"single_instance_allowed": "[%key:common::config_flow::abort::single_instance_allowed%]"
"invalid_unique_id": "Impossible to determine a valid unique id for the device",
"not_unique_id_exist": "A device without a valid UniqueID is already configured. Configuration of multiple instance is not possible"
}
},
"options": {
Expand Down
3 changes: 2 additions & 1 deletion homeassistant/components/asuswrt/translations/en.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
{
"config": {
"abort": {
"single_instance_allowed": "Already configured. Only a single configuration possible."
"invalid_unique_id": "Impossible to determine a valid unique id for the device",
"not_unique_id_exist": "A device without a valid UniqueID is already configured. Configuration of multiple instance is not possible"
},
"error": {
"cannot_connect": "Failed to connect",
Expand Down
Loading