Code Quality improvements for Aussie Broadband (#65408)
Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
This commit is contained in:
parent
be0ef5ad6c
commit
bccfaceedb
6 changed files with 62 additions and 229 deletions
|
@ -15,7 +15,7 @@ from homeassistant.exceptions import ConfigEntryAuthFailed, ConfigEntryNotReady
|
||||||
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
||||||
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
|
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
|
||||||
|
|
||||||
from .const import CONF_SERVICES, DEFAULT_UPDATE_INTERVAL, DOMAIN, SERVICE_ID
|
from .const import DEFAULT_UPDATE_INTERVAL, DOMAIN, SERVICE_ID
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
PLATFORMS = [Platform.SENSOR]
|
PLATFORMS = [Platform.SENSOR]
|
||||||
|
@ -31,17 +31,12 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||||
)
|
)
|
||||||
try:
|
try:
|
||||||
await client.login()
|
await client.login()
|
||||||
all_services = await client.get_services()
|
services = await client.get_services()
|
||||||
except AuthenticationException as exc:
|
except AuthenticationException as exc:
|
||||||
raise ConfigEntryAuthFailed() from exc
|
raise ConfigEntryAuthFailed() from exc
|
||||||
except ClientError as exc:
|
except ClientError as exc:
|
||||||
raise ConfigEntryNotReady() from exc
|
raise ConfigEntryNotReady() from exc
|
||||||
|
|
||||||
# Filter the service list to those that are enabled in options
|
|
||||||
services = [
|
|
||||||
s for s in all_services if str(s["service_id"]) in entry.options[CONF_SERVICES]
|
|
||||||
]
|
|
||||||
|
|
||||||
# Create an appropriate refresh function
|
# Create an appropriate refresh function
|
||||||
def update_data_factory(service_id):
|
def update_data_factory(service_id):
|
||||||
async def async_update_data():
|
async def async_update_data():
|
||||||
|
@ -71,16 +66,10 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||||
"services": services,
|
"services": services,
|
||||||
}
|
}
|
||||||
hass.config_entries.async_setup_platforms(entry, PLATFORMS)
|
hass.config_entries.async_setup_platforms(entry, PLATFORMS)
|
||||||
entry.async_on_unload(entry.add_update_listener(update_listener))
|
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
async def update_listener(hass: HomeAssistant, entry: ConfigEntry) -> None:
|
|
||||||
"""Reload to update options."""
|
|
||||||
await hass.config_entries.async_reload(entry.entry_id)
|
|
||||||
|
|
||||||
|
|
||||||
async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||||
"""Unload the config entry."""
|
"""Unload the config entry."""
|
||||||
unload_ok = await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
|
unload_ok = await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
|
||||||
|
|
|
@ -9,12 +9,10 @@ import voluptuous as vol
|
||||||
|
|
||||||
from homeassistant import config_entries
|
from homeassistant import config_entries
|
||||||
from homeassistant.const import CONF_PASSWORD, CONF_USERNAME
|
from homeassistant.const import CONF_PASSWORD, CONF_USERNAME
|
||||||
from homeassistant.core import callback
|
|
||||||
from homeassistant.data_entry_flow import FlowResult
|
from homeassistant.data_entry_flow import FlowResult
|
||||||
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
||||||
import homeassistant.helpers.config_validation as cv
|
|
||||||
|
|
||||||
from .const import CONF_SERVICES, DOMAIN, SERVICE_ID
|
from .const import CONF_SERVICES, DOMAIN
|
||||||
|
|
||||||
|
|
||||||
class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
||||||
|
@ -39,11 +37,11 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
||||||
)
|
)
|
||||||
try:
|
try:
|
||||||
await self.client.login()
|
await self.client.login()
|
||||||
return None
|
|
||||||
except AuthenticationException:
|
except AuthenticationException:
|
||||||
return {"base": "invalid_auth"}
|
return {"base": "invalid_auth"}
|
||||||
except ClientError:
|
except ClientError:
|
||||||
return {"base": "cannot_connect"}
|
return {"base": "cannot_connect"}
|
||||||
|
return None
|
||||||
|
|
||||||
async def async_step_user(
|
async def async_step_user(
|
||||||
self, user_input: dict[str, Any] | None = None
|
self, user_input: dict[str, Any] | None = None
|
||||||
|
@ -61,15 +59,10 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
||||||
if not self.services:
|
if not self.services:
|
||||||
return self.async_abort(reason="no_services_found")
|
return self.async_abort(reason="no_services_found")
|
||||||
|
|
||||||
if len(self.services) == 1:
|
return self.async_create_entry(
|
||||||
return self.async_create_entry(
|
title=self.data[CONF_USERNAME],
|
||||||
title=self.data[CONF_USERNAME],
|
data=self.data,
|
||||||
data=self.data,
|
)
|
||||||
options={CONF_SERVICES: [str(self.services[0][SERVICE_ID])]},
|
|
||||||
)
|
|
||||||
|
|
||||||
# Account has more than one service, select service to add
|
|
||||||
return await self.async_step_service()
|
|
||||||
|
|
||||||
return self.async_show_form(
|
return self.async_show_form(
|
||||||
step_id="user",
|
step_id="user",
|
||||||
|
@ -82,37 +75,20 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
||||||
errors=errors,
|
errors=errors,
|
||||||
)
|
)
|
||||||
|
|
||||||
async def async_step_service(
|
async def async_step_reauth(self, user_input: dict[str, str]) -> FlowResult:
|
||||||
self, user_input: dict[str, Any] | None = None
|
"""Handle reauth on credential failure."""
|
||||||
) -> FlowResult:
|
self._reauth_username = user_input[CONF_USERNAME]
|
||||||
"""Handle the optional service selection step."""
|
|
||||||
if user_input is not None:
|
|
||||||
return self.async_create_entry(
|
|
||||||
title=self.data[CONF_USERNAME], data=self.data, options=user_input
|
|
||||||
)
|
|
||||||
|
|
||||||
service_options = {str(s[SERVICE_ID]): s["description"] for s in self.services}
|
return await self.async_step_reauth_confirm()
|
||||||
return self.async_show_form(
|
|
||||||
step_id="service",
|
|
||||||
data_schema=vol.Schema(
|
|
||||||
{
|
|
||||||
vol.Required(
|
|
||||||
CONF_SERVICES, default=list(service_options.keys())
|
|
||||||
): cv.multi_select(service_options)
|
|
||||||
}
|
|
||||||
),
|
|
||||||
errors=None,
|
|
||||||
)
|
|
||||||
|
|
||||||
async def async_step_reauth(
|
async def async_step_reauth_confirm(
|
||||||
self, user_input: dict[str, Any] | None = None
|
self, user_input: dict[str, str] | None = None
|
||||||
) -> FlowResult:
|
) -> FlowResult:
|
||||||
"""Handle reauth."""
|
"""Handle users reauth credentials."""
|
||||||
|
|
||||||
errors: dict[str, str] | None = None
|
errors: dict[str, str] | None = None
|
||||||
if user_input and user_input.get(CONF_USERNAME):
|
|
||||||
self._reauth_username = user_input[CONF_USERNAME]
|
|
||||||
|
|
||||||
elif self._reauth_username and user_input and user_input.get(CONF_PASSWORD):
|
if user_input and self._reauth_username:
|
||||||
data = {
|
data = {
|
||||||
CONF_USERNAME: self._reauth_username,
|
CONF_USERNAME: self._reauth_username,
|
||||||
CONF_PASSWORD: user_input[CONF_PASSWORD],
|
CONF_PASSWORD: user_input[CONF_PASSWORD],
|
||||||
|
@ -130,7 +106,7 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
||||||
return self.async_create_entry(title=self._reauth_username, data=data)
|
return self.async_create_entry(title=self._reauth_username, data=data)
|
||||||
|
|
||||||
return self.async_show_form(
|
return self.async_show_form(
|
||||||
step_id="reauth",
|
step_id="reauth_confirm",
|
||||||
description_placeholders={"username": self._reauth_username},
|
description_placeholders={"username": self._reauth_username},
|
||||||
data_schema=vol.Schema(
|
data_schema=vol.Schema(
|
||||||
{
|
{
|
||||||
|
@ -139,46 +115,3 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
||||||
),
|
),
|
||||||
errors=errors,
|
errors=errors,
|
||||||
)
|
)
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
@callback
|
|
||||||
def async_get_options_flow(
|
|
||||||
config_entry: config_entries.ConfigEntry,
|
|
||||||
) -> config_entries.OptionsFlow:
|
|
||||||
"""Get the options flow for this handler."""
|
|
||||||
return OptionsFlowHandler(config_entry)
|
|
||||||
|
|
||||||
|
|
||||||
class OptionsFlowHandler(config_entries.OptionsFlow):
|
|
||||||
"""Options flow for picking services."""
|
|
||||||
|
|
||||||
def __init__(self, config_entry: config_entries.ConfigEntry) -> None:
|
|
||||||
"""Initialize options flow."""
|
|
||||||
self.config_entry = config_entry
|
|
||||||
|
|
||||||
async def async_step_init(self, user_input=None):
|
|
||||||
"""Manage the options."""
|
|
||||||
if user_input is not None:
|
|
||||||
return self.async_create_entry(title="", data=user_input)
|
|
||||||
|
|
||||||
if self.config_entry.state != config_entries.ConfigEntryState.LOADED:
|
|
||||||
return self.async_abort(reason="unknown")
|
|
||||||
data = self.hass.data[DOMAIN][self.config_entry.entry_id]
|
|
||||||
try:
|
|
||||||
services = await data["client"].get_services()
|
|
||||||
except AuthenticationException:
|
|
||||||
return self.async_abort(reason="invalid_auth")
|
|
||||||
except ClientError:
|
|
||||||
return self.async_abort(reason="cannot_connect")
|
|
||||||
service_options = {str(s[SERVICE_ID]): s["description"] for s in services}
|
|
||||||
return self.async_show_form(
|
|
||||||
step_id="init",
|
|
||||||
data_schema=vol.Schema(
|
|
||||||
{
|
|
||||||
vol.Required(
|
|
||||||
CONF_SERVICES,
|
|
||||||
default=self.config_entry.options.get(CONF_SERVICES),
|
|
||||||
): cv.multi_select(service_options),
|
|
||||||
}
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
"""Support for Aussie Broadband metric sensors."""
|
"""Support for Aussie Broadband metric sensors."""
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from typing import Any
|
from collections.abc import Callable
|
||||||
|
from dataclasses import dataclass
|
||||||
|
from typing import Any, cast
|
||||||
|
|
||||||
from homeassistant.components.sensor import (
|
from homeassistant.components.sensor import (
|
||||||
SensorEntity,
|
SensorEntity,
|
||||||
|
@ -14,27 +16,36 @@ from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.helpers.device_registry import DeviceEntryType
|
from homeassistant.helpers.device_registry import DeviceEntryType
|
||||||
from homeassistant.helpers.entity import DeviceInfo
|
from homeassistant.helpers.entity import DeviceInfo
|
||||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
|
from homeassistant.helpers.typing import StateType
|
||||||
from homeassistant.helpers.update_coordinator import CoordinatorEntity
|
from homeassistant.helpers.update_coordinator import CoordinatorEntity
|
||||||
|
|
||||||
from .const import DOMAIN, SERVICE_ID
|
from .const import DOMAIN, SERVICE_ID
|
||||||
|
|
||||||
SENSOR_DESCRIPTIONS: tuple[SensorEntityDescription, ...] = (
|
|
||||||
|
@dataclass
|
||||||
|
class SensorValueEntityDescription(SensorEntityDescription):
|
||||||
|
"""Class describing Aussie Broadband sensor entities."""
|
||||||
|
|
||||||
|
value: Callable = lambda x: x
|
||||||
|
|
||||||
|
|
||||||
|
SENSOR_DESCRIPTIONS: tuple[SensorValueEntityDescription, ...] = (
|
||||||
# Internet Services sensors
|
# Internet Services sensors
|
||||||
SensorEntityDescription(
|
SensorValueEntityDescription(
|
||||||
key="usedMb",
|
key="usedMb",
|
||||||
name="Data Used",
|
name="Data Used",
|
||||||
state_class=SensorStateClass.TOTAL_INCREASING,
|
state_class=SensorStateClass.TOTAL_INCREASING,
|
||||||
native_unit_of_measurement=DATA_MEGABYTES,
|
native_unit_of_measurement=DATA_MEGABYTES,
|
||||||
icon="mdi:network",
|
icon="mdi:network",
|
||||||
),
|
),
|
||||||
SensorEntityDescription(
|
SensorValueEntityDescription(
|
||||||
key="downloadedMb",
|
key="downloadedMb",
|
||||||
name="Downloaded",
|
name="Downloaded",
|
||||||
state_class=SensorStateClass.TOTAL_INCREASING,
|
state_class=SensorStateClass.TOTAL_INCREASING,
|
||||||
native_unit_of_measurement=DATA_MEGABYTES,
|
native_unit_of_measurement=DATA_MEGABYTES,
|
||||||
icon="mdi:download-network",
|
icon="mdi:download-network",
|
||||||
),
|
),
|
||||||
SensorEntityDescription(
|
SensorValueEntityDescription(
|
||||||
key="uploadedMb",
|
key="uploadedMb",
|
||||||
name="Uploaded",
|
name="Uploaded",
|
||||||
state_class=SensorStateClass.TOTAL_INCREASING,
|
state_class=SensorStateClass.TOTAL_INCREASING,
|
||||||
|
@ -42,46 +53,50 @@ SENSOR_DESCRIPTIONS: tuple[SensorEntityDescription, ...] = (
|
||||||
icon="mdi:upload-network",
|
icon="mdi:upload-network",
|
||||||
),
|
),
|
||||||
# Mobile Phone Services sensors
|
# Mobile Phone Services sensors
|
||||||
SensorEntityDescription(
|
SensorValueEntityDescription(
|
||||||
key="national",
|
key="national",
|
||||||
name="National Calls",
|
name="National Calls",
|
||||||
state_class=SensorStateClass.TOTAL_INCREASING,
|
state_class=SensorStateClass.TOTAL_INCREASING,
|
||||||
icon="mdi:phone",
|
icon="mdi:phone",
|
||||||
|
value=lambda x: x.get("calls"),
|
||||||
),
|
),
|
||||||
SensorEntityDescription(
|
SensorValueEntityDescription(
|
||||||
key="mobile",
|
key="mobile",
|
||||||
name="Mobile Calls",
|
name="Mobile Calls",
|
||||||
state_class=SensorStateClass.TOTAL_INCREASING,
|
state_class=SensorStateClass.TOTAL_INCREASING,
|
||||||
icon="mdi:phone",
|
icon="mdi:phone",
|
||||||
|
value=lambda x: x.get("calls"),
|
||||||
),
|
),
|
||||||
SensorEntityDescription(
|
SensorValueEntityDescription(
|
||||||
key="international",
|
key="international",
|
||||||
name="International Calls",
|
name="International Calls",
|
||||||
entity_registry_enabled_default=False,
|
entity_registry_enabled_default=False,
|
||||||
state_class=SensorStateClass.TOTAL_INCREASING,
|
state_class=SensorStateClass.TOTAL_INCREASING,
|
||||||
icon="mdi:phone-plus",
|
icon="mdi:phone-plus",
|
||||||
),
|
),
|
||||||
SensorEntityDescription(
|
SensorValueEntityDescription(
|
||||||
key="sms",
|
key="sms",
|
||||||
name="SMS Sent",
|
name="SMS Sent",
|
||||||
state_class=SensorStateClass.TOTAL_INCREASING,
|
state_class=SensorStateClass.TOTAL_INCREASING,
|
||||||
icon="mdi:message-processing",
|
icon="mdi:message-processing",
|
||||||
|
value=lambda x: x.get("calls"),
|
||||||
),
|
),
|
||||||
SensorEntityDescription(
|
SensorValueEntityDescription(
|
||||||
key="internet",
|
key="internet",
|
||||||
name="Data Used",
|
name="Data Used",
|
||||||
state_class=SensorStateClass.TOTAL_INCREASING,
|
state_class=SensorStateClass.TOTAL_INCREASING,
|
||||||
native_unit_of_measurement=DATA_KILOBYTES,
|
native_unit_of_measurement=DATA_KILOBYTES,
|
||||||
icon="mdi:network",
|
icon="mdi:network",
|
||||||
|
value=lambda x: x.get("kbytes"),
|
||||||
),
|
),
|
||||||
SensorEntityDescription(
|
SensorValueEntityDescription(
|
||||||
key="voicemail",
|
key="voicemail",
|
||||||
name="Voicemail Calls",
|
name="Voicemail Calls",
|
||||||
entity_registry_enabled_default=False,
|
entity_registry_enabled_default=False,
|
||||||
state_class=SensorStateClass.TOTAL_INCREASING,
|
state_class=SensorStateClass.TOTAL_INCREASING,
|
||||||
icon="mdi:phone",
|
icon="mdi:phone",
|
||||||
),
|
),
|
||||||
SensorEntityDescription(
|
SensorValueEntityDescription(
|
||||||
key="other",
|
key="other",
|
||||||
name="Other Calls",
|
name="Other Calls",
|
||||||
entity_registry_enabled_default=False,
|
entity_registry_enabled_default=False,
|
||||||
|
@ -89,13 +104,13 @@ SENSOR_DESCRIPTIONS: tuple[SensorEntityDescription, ...] = (
|
||||||
icon="mdi:phone",
|
icon="mdi:phone",
|
||||||
),
|
),
|
||||||
# Generic sensors
|
# Generic sensors
|
||||||
SensorEntityDescription(
|
SensorValueEntityDescription(
|
||||||
key="daysTotal",
|
key="daysTotal",
|
||||||
name="Billing Cycle Length",
|
name="Billing Cycle Length",
|
||||||
native_unit_of_measurement=TIME_DAYS,
|
native_unit_of_measurement=TIME_DAYS,
|
||||||
icon="mdi:calendar-range",
|
icon="mdi:calendar-range",
|
||||||
),
|
),
|
||||||
SensorEntityDescription(
|
SensorValueEntityDescription(
|
||||||
key="daysRemaining",
|
key="daysRemaining",
|
||||||
name="Billing Cycle Remaining",
|
name="Billing Cycle Remaining",
|
||||||
native_unit_of_measurement=TIME_DAYS,
|
native_unit_of_measurement=TIME_DAYS,
|
||||||
|
@ -122,8 +137,10 @@ async def async_setup_entry(
|
||||||
class AussieBroadandSensorEntity(CoordinatorEntity, SensorEntity):
|
class AussieBroadandSensorEntity(CoordinatorEntity, SensorEntity):
|
||||||
"""Base class for Aussie Broadband metric sensors."""
|
"""Base class for Aussie Broadband metric sensors."""
|
||||||
|
|
||||||
|
entity_description: SensorValueEntityDescription
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self, service: dict[str, Any], description: SensorEntityDescription
|
self, service: dict[str, Any], description: SensorValueEntityDescription
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Initialize the sensor."""
|
"""Initialize the sensor."""
|
||||||
super().__init__(service["coordinator"])
|
super().__init__(service["coordinator"])
|
||||||
|
@ -134,16 +151,13 @@ class AussieBroadandSensorEntity(CoordinatorEntity, SensorEntity):
|
||||||
entry_type=DeviceEntryType.SERVICE,
|
entry_type=DeviceEntryType.SERVICE,
|
||||||
identifiers={(DOMAIN, service[SERVICE_ID])},
|
identifiers={(DOMAIN, service[SERVICE_ID])},
|
||||||
manufacturer="Aussie Broadband",
|
manufacturer="Aussie Broadband",
|
||||||
configuration_url=f"https://my.aussiebroadband.com.au/#/{service['name']}/{service[SERVICE_ID]}/",
|
configuration_url=f"https://my.aussiebroadband.com.au/#/{service['name'].lower()}/{service[SERVICE_ID]}/",
|
||||||
name=service["description"],
|
name=service["description"],
|
||||||
model=service["name"],
|
model=service["name"],
|
||||||
)
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def native_value(self):
|
def native_value(self) -> StateType:
|
||||||
"""Return the state of the sensor."""
|
"""Return the state of the sensor."""
|
||||||
if self.entity_description.key == "internet":
|
parent = self.coordinator.data[self.entity_description.key]
|
||||||
return self.coordinator.data[self.entity_description.key].get("kbytes")
|
return cast(StateType, self.entity_description.value(parent))
|
||||||
if self.entity_description.key in ("national", "mobile", "sms"):
|
|
||||||
return self.coordinator.data[self.entity_description.key].get("calls")
|
|
||||||
return self.coordinator.data[self.entity_description.key]
|
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
"services": "Services"
|
"services": "Services"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"reauth": {
|
"reauth_confirm": {
|
||||||
"title": "[%key:common::config_flow::title::reauth%]",
|
"title": "[%key:common::config_flow::title::reauth%]",
|
||||||
"description": "Update password for {username}",
|
"description": "Update password for {username}",
|
||||||
"data": {
|
"data": {
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
"unknown": "Unexpected error"
|
"unknown": "Unexpected error"
|
||||||
},
|
},
|
||||||
"step": {
|
"step": {
|
||||||
"reauth": {
|
"reauth_confirm": {
|
||||||
"data": {
|
"data": {
|
||||||
"password": "Password"
|
"password": "Password"
|
||||||
},
|
},
|
||||||
|
|
|
@ -4,8 +4,8 @@ from unittest.mock import patch
|
||||||
from aiohttp import ClientConnectionError
|
from aiohttp import ClientConnectionError
|
||||||
from aussiebb.asyncio import AuthenticationException
|
from aussiebb.asyncio import AuthenticationException
|
||||||
|
|
||||||
from homeassistant import config_entries, setup
|
from homeassistant import config_entries
|
||||||
from homeassistant.components.aussie_broadband.const import CONF_SERVICES, DOMAIN
|
from homeassistant.components.aussie_broadband.const import DOMAIN
|
||||||
from homeassistant.const import CONF_PASSWORD, CONF_USERNAME
|
from homeassistant.const import CONF_PASSWORD, CONF_USERNAME
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.data_entry_flow import (
|
from homeassistant.data_entry_flow import (
|
||||||
|
@ -14,7 +14,7 @@ from homeassistant.data_entry_flow import (
|
||||||
RESULT_TYPE_FORM,
|
RESULT_TYPE_FORM,
|
||||||
)
|
)
|
||||||
|
|
||||||
from .common import FAKE_DATA, FAKE_SERVICES, setup_platform
|
from .common import FAKE_DATA, FAKE_SERVICES
|
||||||
|
|
||||||
TEST_USERNAME = FAKE_DATA[CONF_USERNAME]
|
TEST_USERNAME = FAKE_DATA[CONF_USERNAME]
|
||||||
TEST_PASSWORD = FAKE_DATA[CONF_PASSWORD]
|
TEST_PASSWORD = FAKE_DATA[CONF_PASSWORD]
|
||||||
|
@ -31,7 +31,7 @@ async def test_form(hass: HomeAssistant) -> None:
|
||||||
with patch("aussiebb.asyncio.AussieBB.__init__", return_value=None), patch(
|
with patch("aussiebb.asyncio.AussieBB.__init__", return_value=None), patch(
|
||||||
"aussiebb.asyncio.AussieBB.login", return_value=True
|
"aussiebb.asyncio.AussieBB.login", return_value=True
|
||||||
), patch(
|
), patch(
|
||||||
"aussiebb.asyncio.AussieBB.get_services", return_value=[FAKE_SERVICES[0]]
|
"aussiebb.asyncio.AussieBB.get_services", return_value=FAKE_SERVICES
|
||||||
), patch(
|
), patch(
|
||||||
"homeassistant.components.aussie_broadband.async_setup_entry",
|
"homeassistant.components.aussie_broadband.async_setup_entry",
|
||||||
return_value=True,
|
return_value=True,
|
||||||
|
@ -45,7 +45,6 @@ async def test_form(hass: HomeAssistant) -> None:
|
||||||
assert result2["type"] == RESULT_TYPE_CREATE_ENTRY
|
assert result2["type"] == RESULT_TYPE_CREATE_ENTRY
|
||||||
assert result2["title"] == TEST_USERNAME
|
assert result2["title"] == TEST_USERNAME
|
||||||
assert result2["data"] == FAKE_DATA
|
assert result2["data"] == FAKE_DATA
|
||||||
assert result2["options"] == {CONF_SERVICES: ["12345678"]}
|
|
||||||
assert len(mock_setup_entry.mock_calls) == 1
|
assert len(mock_setup_entry.mock_calls) == 1
|
||||||
|
|
||||||
|
|
||||||
|
@ -117,46 +116,6 @@ async def test_no_services(hass: HomeAssistant) -> None:
|
||||||
assert len(mock_setup_entry.mock_calls) == 0
|
assert len(mock_setup_entry.mock_calls) == 0
|
||||||
|
|
||||||
|
|
||||||
async def test_form_multiple_services(hass: HomeAssistant) -> None:
|
|
||||||
"""Test the config flow with multiple services."""
|
|
||||||
result = await hass.config_entries.flow.async_init(
|
|
||||||
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
|
||||||
)
|
|
||||||
assert result["type"] == RESULT_TYPE_FORM
|
|
||||||
assert result["errors"] is None
|
|
||||||
|
|
||||||
with patch("aussiebb.asyncio.AussieBB.__init__", return_value=None), patch(
|
|
||||||
"aussiebb.asyncio.AussieBB.login", return_value=True
|
|
||||||
), patch("aussiebb.asyncio.AussieBB.get_services", return_value=FAKE_SERVICES):
|
|
||||||
result2 = await hass.config_entries.flow.async_configure(
|
|
||||||
result["flow_id"],
|
|
||||||
FAKE_DATA,
|
|
||||||
)
|
|
||||||
await hass.async_block_till_done()
|
|
||||||
|
|
||||||
assert result2["type"] == RESULT_TYPE_FORM
|
|
||||||
assert result2["step_id"] == "service"
|
|
||||||
assert result2["errors"] is None
|
|
||||||
|
|
||||||
with patch(
|
|
||||||
"homeassistant.components.aussie_broadband.async_setup_entry",
|
|
||||||
return_value=True,
|
|
||||||
) as mock_setup_entry:
|
|
||||||
result3 = await hass.config_entries.flow.async_configure(
|
|
||||||
result["flow_id"],
|
|
||||||
{CONF_SERVICES: [FAKE_SERVICES[1]["service_id"]]},
|
|
||||||
)
|
|
||||||
await hass.async_block_till_done()
|
|
||||||
|
|
||||||
assert result3["type"] == RESULT_TYPE_CREATE_ENTRY
|
|
||||||
assert result3["title"] == TEST_USERNAME
|
|
||||||
assert result3["data"] == FAKE_DATA
|
|
||||||
assert result3["options"] == {
|
|
||||||
CONF_SERVICES: [FAKE_SERVICES[1]["service_id"]],
|
|
||||||
}
|
|
||||||
assert len(mock_setup_entry.mock_calls) == 1
|
|
||||||
|
|
||||||
|
|
||||||
async def test_form_invalid_auth(hass: HomeAssistant) -> None:
|
async def test_form_invalid_auth(hass: HomeAssistant) -> None:
|
||||||
"""Test invalid auth is handled."""
|
"""Test invalid auth is handled."""
|
||||||
result1 = await hass.config_entries.flow.async_init(
|
result1 = await hass.config_entries.flow.async_init(
|
||||||
|
@ -196,8 +155,6 @@ async def test_form_network_issue(hass: HomeAssistant) -> None:
|
||||||
async def test_reauth(hass: HomeAssistant) -> None:
|
async def test_reauth(hass: HomeAssistant) -> None:
|
||||||
"""Test reauth flow."""
|
"""Test reauth flow."""
|
||||||
|
|
||||||
await setup.async_setup_component(hass, "persistent_notification", {})
|
|
||||||
|
|
||||||
# Test reauth but the entry doesn't exist
|
# Test reauth but the entry doesn't exist
|
||||||
result1 = await hass.config_entries.flow.async_init(
|
result1 = await hass.config_entries.flow.async_init(
|
||||||
DOMAIN, context={"source": config_entries.SOURCE_REAUTH}, data=FAKE_DATA
|
DOMAIN, context={"source": config_entries.SOURCE_REAUTH}, data=FAKE_DATA
|
||||||
|
@ -229,7 +186,7 @@ async def test_reauth(hass: HomeAssistant) -> None:
|
||||||
context={"source": config_entries.SOURCE_REAUTH},
|
context={"source": config_entries.SOURCE_REAUTH},
|
||||||
data=FAKE_DATA,
|
data=FAKE_DATA,
|
||||||
)
|
)
|
||||||
assert result5["step_id"] == "reauth"
|
assert result5["step_id"] == "reauth_confirm"
|
||||||
|
|
||||||
with patch("aussiebb.asyncio.AussieBB.__init__", return_value=None), patch(
|
with patch("aussiebb.asyncio.AussieBB.__init__", return_value=None), patch(
|
||||||
"aussiebb.asyncio.AussieBB.login", side_effect=AuthenticationException()
|
"aussiebb.asyncio.AussieBB.login", side_effect=AuthenticationException()
|
||||||
|
@ -243,7 +200,7 @@ async def test_reauth(hass: HomeAssistant) -> None:
|
||||||
)
|
)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
assert result6["step_id"] == "reauth"
|
assert result6["step_id"] == "reauth_confirm"
|
||||||
|
|
||||||
# Test successful reauth
|
# Test successful reauth
|
||||||
with patch("aussiebb.asyncio.AussieBB.__init__", return_value=None), patch(
|
with patch("aussiebb.asyncio.AussieBB.__init__", return_value=None), patch(
|
||||||
|
@ -260,63 +217,3 @@ async def test_reauth(hass: HomeAssistant) -> None:
|
||||||
|
|
||||||
assert result7["type"] == "abort"
|
assert result7["type"] == "abort"
|
||||||
assert result7["reason"] == "reauth_successful"
|
assert result7["reason"] == "reauth_successful"
|
||||||
|
|
||||||
|
|
||||||
async def test_options_flow(hass):
|
|
||||||
"""Test options flow."""
|
|
||||||
entry = await setup_platform(hass)
|
|
||||||
|
|
||||||
with patch("aussiebb.asyncio.AussieBB.get_services", return_value=FAKE_SERVICES):
|
|
||||||
|
|
||||||
result1 = await hass.config_entries.options.async_init(entry.entry_id)
|
|
||||||
assert result1["type"] == RESULT_TYPE_FORM
|
|
||||||
assert result1["step_id"] == "init"
|
|
||||||
|
|
||||||
result2 = await hass.config_entries.options.async_configure(
|
|
||||||
result1["flow_id"],
|
|
||||||
user_input={CONF_SERVICES: []},
|
|
||||||
)
|
|
||||||
assert result2["type"] == RESULT_TYPE_CREATE_ENTRY
|
|
||||||
assert entry.options == {CONF_SERVICES: []}
|
|
||||||
|
|
||||||
|
|
||||||
async def test_options_flow_auth_failure(hass):
|
|
||||||
"""Test options flow with auth failure."""
|
|
||||||
|
|
||||||
entry = await setup_platform(hass)
|
|
||||||
|
|
||||||
with patch(
|
|
||||||
"aussiebb.asyncio.AussieBB.get_services", side_effect=AuthenticationException()
|
|
||||||
):
|
|
||||||
|
|
||||||
result1 = await hass.config_entries.options.async_init(entry.entry_id)
|
|
||||||
assert result1["type"] == RESULT_TYPE_ABORT
|
|
||||||
assert result1["reason"] == "invalid_auth"
|
|
||||||
|
|
||||||
|
|
||||||
async def test_options_flow_network_failure(hass):
|
|
||||||
"""Test options flow with connectivity failure."""
|
|
||||||
|
|
||||||
entry = await setup_platform(hass)
|
|
||||||
|
|
||||||
with patch(
|
|
||||||
"aussiebb.asyncio.AussieBB.get_services", side_effect=ClientConnectionError()
|
|
||||||
):
|
|
||||||
|
|
||||||
result1 = await hass.config_entries.options.async_init(entry.entry_id)
|
|
||||||
assert result1["type"] == RESULT_TYPE_ABORT
|
|
||||||
assert result1["reason"] == "cannot_connect"
|
|
||||||
|
|
||||||
|
|
||||||
async def test_options_flow_not_loaded(hass):
|
|
||||||
"""Test the options flow aborts when the entry has unloaded due to a reauth."""
|
|
||||||
|
|
||||||
entry = await setup_platform(hass)
|
|
||||||
|
|
||||||
with patch(
|
|
||||||
"aussiebb.asyncio.AussieBB.get_services", side_effect=AuthenticationException()
|
|
||||||
):
|
|
||||||
entry.state = config_entries.ConfigEntryState.NOT_LOADED
|
|
||||||
result1 = await hass.config_entries.options.async_init(entry.entry_id)
|
|
||||||
assert result1["type"] == RESULT_TYPE_ABORT
|
|
||||||
assert result1["reason"] == "unknown"
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue