mirror of
https://github.com/home-assistant/core.git
synced 2025-06-09 23:57:08 +00:00
Clean up ondilo ico oauth2 (#139927)
This commit is contained in:
parent
edd2d4c349
commit
27964e16c1
@ -1,27 +1,37 @@
|
|||||||
"""The Ondilo ICO integration."""
|
"""The Ondilo ICO integration."""
|
||||||
|
|
||||||
|
from homeassistant.components.application_credentials import (
|
||||||
|
ClientCredential,
|
||||||
|
async_import_client_credential,
|
||||||
|
)
|
||||||
from homeassistant.config_entries import ConfigEntry
|
from homeassistant.config_entries import ConfigEntry
|
||||||
from homeassistant.const import Platform
|
from homeassistant.const import Platform
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.helpers import config_entry_oauth2_flow
|
from homeassistant.helpers import config_entry_oauth2_flow, config_validation as cv
|
||||||
|
from homeassistant.helpers.typing import ConfigType
|
||||||
|
|
||||||
from .api import OndiloClient
|
from .api import OndiloClient
|
||||||
from .config_flow import OndiloIcoOAuth2FlowHandler
|
from .const import DOMAIN, OAUTH2_CLIENT_ID, OAUTH2_CLIENT_SECRET
|
||||||
from .const import DOMAIN
|
|
||||||
from .coordinator import OndiloIcoPoolsCoordinator
|
from .coordinator import OndiloIcoPoolsCoordinator
|
||||||
from .oauth_impl import OndiloOauth2Implementation
|
|
||||||
|
|
||||||
|
CONFIG_SCHEMA = cv.config_entry_only_config_schema(DOMAIN)
|
||||||
PLATFORMS = [Platform.SENSOR]
|
PLATFORMS = [Platform.SENSOR]
|
||||||
|
|
||||||
|
|
||||||
|
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
|
||||||
|
"""Set up the Ondilo ICO integration."""
|
||||||
|
# Import the default client credential.
|
||||||
|
await async_import_client_credential(
|
||||||
|
hass,
|
||||||
|
DOMAIN,
|
||||||
|
ClientCredential(OAUTH2_CLIENT_ID, OAUTH2_CLIENT_SECRET, name="Ondilo ICO"),
|
||||||
|
)
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||||
"""Set up Ondilo ICO from a config entry."""
|
"""Set up Ondilo ICO from a config entry."""
|
||||||
|
|
||||||
OndiloIcoOAuth2FlowHandler.async_register_implementation(
|
|
||||||
hass,
|
|
||||||
OndiloOauth2Implementation(hass),
|
|
||||||
)
|
|
||||||
|
|
||||||
implementation = (
|
implementation = (
|
||||||
await config_entry_oauth2_flow.async_get_config_entry_implementation(
|
await config_entry_oauth2_flow.async_get_config_entry_implementation(
|
||||||
hass, entry
|
hass, entry
|
||||||
|
@ -1,15 +1,12 @@
|
|||||||
"""API for Ondilo ICO bound to Home Assistant OAuth."""
|
"""API for Ondilo ICO bound to Home Assistant OAuth."""
|
||||||
|
|
||||||
from asyncio import run_coroutine_threadsafe
|
from asyncio import run_coroutine_threadsafe
|
||||||
import logging
|
|
||||||
|
|
||||||
from ondilo import Ondilo
|
from ondilo import Ondilo
|
||||||
|
|
||||||
from homeassistant import config_entries, core
|
from homeassistant import config_entries, core
|
||||||
from homeassistant.helpers import config_entry_oauth2_flow
|
from homeassistant.helpers import config_entry_oauth2_flow
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
|
|
||||||
class OndiloClient(Ondilo):
|
class OndiloClient(Ondilo):
|
||||||
"""Provide Ondilo ICO authentication tied to an OAuth2 based config entry."""
|
"""Provide Ondilo ICO authentication tied to an OAuth2 based config entry."""
|
||||||
|
@ -0,0 +1,14 @@
|
|||||||
|
"""Application credentials platform for Ondilo ICO."""
|
||||||
|
|
||||||
|
from homeassistant.components.application_credentials import AuthorizationServer
|
||||||
|
from homeassistant.core import HomeAssistant
|
||||||
|
|
||||||
|
from .const import OAUTH2_AUTHORIZE, OAUTH2_TOKEN
|
||||||
|
|
||||||
|
|
||||||
|
async def async_get_authorization_server(hass: HomeAssistant) -> AuthorizationServer:
|
||||||
|
"""Return authorization server."""
|
||||||
|
return AuthorizationServer(
|
||||||
|
authorize_url=OAUTH2_AUTHORIZE,
|
||||||
|
token_url=OAUTH2_TOKEN,
|
||||||
|
)
|
@ -3,11 +3,14 @@
|
|||||||
import logging
|
import logging
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
|
from homeassistant.components.application_credentials import (
|
||||||
|
ClientCredential,
|
||||||
|
async_import_client_credential,
|
||||||
|
)
|
||||||
from homeassistant.config_entries import ConfigFlowResult
|
from homeassistant.config_entries import ConfigFlowResult
|
||||||
from homeassistant.helpers.config_entry_oauth2_flow import AbstractOAuth2FlowHandler
|
from homeassistant.helpers.config_entry_oauth2_flow import AbstractOAuth2FlowHandler
|
||||||
|
|
||||||
from .const import DOMAIN
|
from .const import DOMAIN, OAUTH2_CLIENT_ID, OAUTH2_CLIENT_SECRET
|
||||||
from .oauth_impl import OndiloOauth2Implementation
|
|
||||||
|
|
||||||
|
|
||||||
class OndiloIcoOAuth2FlowHandler(AbstractOAuth2FlowHandler, domain=DOMAIN):
|
class OndiloIcoOAuth2FlowHandler(AbstractOAuth2FlowHandler, domain=DOMAIN):
|
||||||
@ -18,14 +21,13 @@ class OndiloIcoOAuth2FlowHandler(AbstractOAuth2FlowHandler, domain=DOMAIN):
|
|||||||
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
|
||||||
) -> ConfigFlowResult:
|
) -> ConfigFlowResult:
|
||||||
"""Handle a flow initialized by the user."""
|
"""Handle a flow start."""
|
||||||
await self.async_set_unique_id(DOMAIN)
|
# Import the default client credential.
|
||||||
|
await async_import_client_credential(
|
||||||
self.async_register_implementation(
|
|
||||||
self.hass,
|
self.hass,
|
||||||
OndiloOauth2Implementation(self.hass),
|
DOMAIN,
|
||||||
|
ClientCredential(OAUTH2_CLIENT_ID, OAUTH2_CLIENT_SECRET, name="Ondilo ICO"),
|
||||||
)
|
)
|
||||||
|
|
||||||
return await super().async_step_user(user_input)
|
return await super().async_step_user(user_input)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
@ -4,5 +4,5 @@ DOMAIN = "ondilo_ico"
|
|||||||
|
|
||||||
OAUTH2_AUTHORIZE = "https://interop.ondilo.com/oauth2/authorize"
|
OAUTH2_AUTHORIZE = "https://interop.ondilo.com/oauth2/authorize"
|
||||||
OAUTH2_TOKEN = "https://interop.ondilo.com/oauth2/token"
|
OAUTH2_TOKEN = "https://interop.ondilo.com/oauth2/token"
|
||||||
OAUTH2_CLIENTID = "customer_api"
|
OAUTH2_CLIENT_ID = "customer_api"
|
||||||
OAUTH2_CLIENTSECRET = ""
|
OAUTH2_CLIENT_SECRET = ""
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
"name": "Ondilo ICO",
|
"name": "Ondilo ICO",
|
||||||
"codeowners": ["@JeromeHXP"],
|
"codeowners": ["@JeromeHXP"],
|
||||||
"config_flow": true,
|
"config_flow": true,
|
||||||
"dependencies": ["auth"],
|
"dependencies": ["application_credentials"],
|
||||||
"documentation": "https://www.home-assistant.io/integrations/ondilo_ico",
|
"documentation": "https://www.home-assistant.io/integrations/ondilo_ico",
|
||||||
"integration_type": "hub",
|
"integration_type": "hub",
|
||||||
"iot_class": "cloud_polling",
|
"iot_class": "cloud_polling",
|
||||||
|
@ -1,32 +0,0 @@
|
|||||||
"""Local implementation of OAuth2 specific to Ondilo to hard code client id and secret and return a proper name."""
|
|
||||||
|
|
||||||
from homeassistant.core import HomeAssistant
|
|
||||||
from homeassistant.helpers.config_entry_oauth2_flow import LocalOAuth2Implementation
|
|
||||||
|
|
||||||
from .const import (
|
|
||||||
DOMAIN,
|
|
||||||
OAUTH2_AUTHORIZE,
|
|
||||||
OAUTH2_CLIENTID,
|
|
||||||
OAUTH2_CLIENTSECRET,
|
|
||||||
OAUTH2_TOKEN,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class OndiloOauth2Implementation(LocalOAuth2Implementation):
|
|
||||||
"""Local implementation of OAuth2 specific to Ondilo to hard code client id and secret and return a proper name."""
|
|
||||||
|
|
||||||
def __init__(self, hass: HomeAssistant) -> None:
|
|
||||||
"""Just init default class with default values."""
|
|
||||||
super().__init__(
|
|
||||||
hass,
|
|
||||||
DOMAIN,
|
|
||||||
OAUTH2_CLIENTID,
|
|
||||||
OAUTH2_CLIENTSECRET,
|
|
||||||
OAUTH2_AUTHORIZE,
|
|
||||||
OAUTH2_TOKEN,
|
|
||||||
)
|
|
||||||
|
|
||||||
@property
|
|
||||||
def name(self) -> str:
|
|
||||||
"""Name of the implementation."""
|
|
||||||
return "Ondilo"
|
|
@ -25,6 +25,7 @@ APPLICATION_CREDENTIALS = [
|
|||||||
"neato",
|
"neato",
|
||||||
"nest",
|
"nest",
|
||||||
"netatmo",
|
"netatmo",
|
||||||
|
"ondilo_ico",
|
||||||
"onedrive",
|
"onedrive",
|
||||||
"point",
|
"point",
|
||||||
"senz",
|
"senz",
|
||||||
|
@ -7,6 +7,7 @@ from unittest.mock import MagicMock, patch
|
|||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from homeassistant.components.ondilo_ico.const import DOMAIN
|
from homeassistant.components.ondilo_ico.const import DOMAIN
|
||||||
|
from homeassistant.util.json import JsonArrayType
|
||||||
|
|
||||||
from tests.common import (
|
from tests.common import (
|
||||||
MockConfigEntry,
|
MockConfigEntry,
|
||||||
@ -71,7 +72,7 @@ def ico_details2() -> dict[str, Any]:
|
|||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope="package")
|
@pytest.fixture(scope="package")
|
||||||
def last_measures() -> list[dict[str, Any]]:
|
def last_measures() -> JsonArrayType:
|
||||||
"""Pool measurements."""
|
"""Pool measurements."""
|
||||||
return load_json_array_fixture("last_measures.json", DOMAIN)
|
return load_json_array_fixture("last_measures.json", DOMAIN)
|
||||||
|
|
||||||
|
@ -4,15 +4,13 @@ from unittest.mock import patch
|
|||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from homeassistant import config_entries, setup
|
from homeassistant import config_entries
|
||||||
from homeassistant.components.ondilo_ico.const import (
|
from homeassistant.components.ondilo_ico.const import (
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
OAUTH2_AUTHORIZE,
|
OAUTH2_AUTHORIZE,
|
||||||
OAUTH2_CLIENTID,
|
OAUTH2_CLIENT_ID as CLIENT_ID,
|
||||||
OAUTH2_CLIENTSECRET,
|
|
||||||
OAUTH2_TOKEN,
|
OAUTH2_TOKEN,
|
||||||
)
|
)
|
||||||
from homeassistant.const import CONF_CLIENT_ID, CONF_CLIENT_SECRET
|
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.data_entry_flow import FlowResultType
|
from homeassistant.data_entry_flow import FlowResultType
|
||||||
from homeassistant.helpers import config_entry_oauth2_flow
|
from homeassistant.helpers import config_entry_oauth2_flow
|
||||||
@ -21,13 +19,12 @@ from tests.common import MockConfigEntry
|
|||||||
from tests.test_util.aiohttp import AiohttpClientMocker
|
from tests.test_util.aiohttp import AiohttpClientMocker
|
||||||
from tests.typing import ClientSessionGenerator
|
from tests.typing import ClientSessionGenerator
|
||||||
|
|
||||||
CLIENT_ID = OAUTH2_CLIENTID
|
|
||||||
CLIENT_SECRET = OAUTH2_CLIENTSECRET
|
|
||||||
|
|
||||||
|
async def test_abort_if_existing_entry(
|
||||||
async def test_abort_if_existing_entry(hass: HomeAssistant) -> None:
|
hass: HomeAssistant, config_entry: MockConfigEntry
|
||||||
|
) -> None:
|
||||||
"""Check flow abort when an entry already exist."""
|
"""Check flow abort when an entry already exist."""
|
||||||
MockConfigEntry(domain=DOMAIN).add_to_hass(hass)
|
config_entry.add_to_hass(hass)
|
||||||
|
|
||||||
result = await hass.config_entries.flow.async_init(
|
result = await hass.config_entries.flow.async_init(
|
||||||
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
||||||
@ -43,15 +40,6 @@ async def test_full_flow(
|
|||||||
aioclient_mock: AiohttpClientMocker,
|
aioclient_mock: AiohttpClientMocker,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Check full flow."""
|
"""Check full flow."""
|
||||||
assert await setup.async_setup_component(
|
|
||||||
hass,
|
|
||||||
DOMAIN,
|
|
||||||
{
|
|
||||||
DOMAIN: {CONF_CLIENT_ID: CLIENT_ID, CONF_CLIENT_SECRET: CLIENT_SECRET},
|
|
||||||
"http": {"base_url": "https://example.com"},
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
result = await hass.config_entries.flow.async_init(
|
result = await hass.config_entries.flow.async_init(
|
||||||
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
||||||
)
|
)
|
||||||
|
@ -45,7 +45,9 @@ async def test_no_ico_for_one_pool(
|
|||||||
# Only the second pool is created
|
# Only the second pool is created
|
||||||
assert len(hass.states.async_all()) == 7
|
assert len(hass.states.async_all()) == 7
|
||||||
assert hass.states.get("sensor.pool_1_temperature") is None
|
assert hass.states.get("sensor.pool_1_temperature") is None
|
||||||
assert hass.states.get("sensor.pool_2_rssi").state == next(
|
state = hass.states.get("sensor.pool_2_rssi")
|
||||||
|
assert state is not None
|
||||||
|
assert state.state == next(
|
||||||
str(item["value"]) for item in last_measures if item["data_type"] == "rssi"
|
str(item["value"]) for item in last_measures if item["data_type"] == "rssi"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user