Remove ambiclimate integration (#116410)

This commit is contained in:
G Johansson 2024-05-06 22:15:04 +02:00 committed by GitHub
parent 2b6dd59cfc
commit b3008b074e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
19 changed files with 0 additions and 778 deletions

View file

@ -64,7 +64,6 @@ omit =
homeassistant/components/alarmdecoder/sensor.py
homeassistant/components/alpha_vantage/sensor.py
homeassistant/components/amazon_polly/*
homeassistant/components/ambiclimate/climate.py
homeassistant/components/ambient_station/__init__.py
homeassistant/components/ambient_station/binary_sensor.py
homeassistant/components/ambient_station/entity.py

View file

@ -65,7 +65,6 @@ homeassistant.components.alexa.*
homeassistant.components.alpha_vantage.*
homeassistant.components.amazon_polly.*
homeassistant.components.amberelectric.*
homeassistant.components.ambiclimate.*
homeassistant.components.ambient_network.*
homeassistant.components.ambient_station.*
homeassistant.components.amcrest.*

View file

@ -88,8 +88,6 @@ build.json @home-assistant/supervisor
/tests/components/alexa/ @home-assistant/cloud @ochlocracy @jbouwh
/homeassistant/components/amberelectric/ @madpilot
/tests/components/amberelectric/ @madpilot
/homeassistant/components/ambiclimate/ @danielhiversen
/tests/components/ambiclimate/ @danielhiversen
/homeassistant/components/ambient_network/ @thomaskistler
/tests/components/ambient_network/ @thomaskistler
/homeassistant/components/ambient_station/ @bachya

View file

@ -1,59 +0,0 @@
"""Support for Ambiclimate devices."""
import voluptuous as vol
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_CLIENT_ID, CONF_CLIENT_SECRET, Platform
from homeassistant.core import HomeAssistant
from homeassistant.helpers import config_validation as cv, issue_registry as ir
from homeassistant.helpers.typing import ConfigType
from . import config_flow
from .const import DOMAIN
CONFIG_SCHEMA = vol.Schema(
{
DOMAIN: vol.Schema(
{
vol.Required(CONF_CLIENT_ID): cv.string,
vol.Required(CONF_CLIENT_SECRET): cv.string,
}
)
},
extra=vol.ALLOW_EXTRA,
)
PLATFORMS = [Platform.CLIMATE]
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
"""Set up Ambiclimate components."""
if DOMAIN not in config:
return True
conf = config[DOMAIN]
config_flow.register_flow_implementation(
hass, conf[CONF_CLIENT_ID], conf[CONF_CLIENT_SECRET]
)
return True
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Set up Ambiclimate from a config entry."""
ir.async_create_issue(
hass,
DOMAIN,
DOMAIN,
breaks_in_ha_version="2024.4.0",
is_fixable=False,
severity=ir.IssueSeverity.WARNING,
translation_key="integration_removed",
translation_placeholders={
"entries": "/config/integrations/integration/ambiclimate",
},
)
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
return True

View file

@ -1,211 +0,0 @@
"""Support for Ambiclimate ac."""
from __future__ import annotations
import asyncio
import logging
from typing import Any
import ambiclimate
from ambiclimate import AmbiclimateDevice
import voluptuous as vol
from homeassistant.components.climate import (
ClimateEntity,
ClimateEntityFeature,
HVACMode,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import (
ATTR_NAME,
ATTR_TEMPERATURE,
CONF_CLIENT_ID,
CONF_CLIENT_SECRET,
UnitOfTemperature,
)
from homeassistant.core import HomeAssistant, ServiceCall
from homeassistant.helpers import config_validation as cv
from homeassistant.helpers.aiohttp_client import async_get_clientsession
from homeassistant.helpers.device_registry import DeviceInfo
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.storage import Store
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
from .const import (
ATTR_VALUE,
DOMAIN,
SERVICE_COMFORT_FEEDBACK,
SERVICE_COMFORT_MODE,
SERVICE_TEMPERATURE_MODE,
STORAGE_KEY,
STORAGE_VERSION,
)
_LOGGER = logging.getLogger(__name__)
SEND_COMFORT_FEEDBACK_SCHEMA = vol.Schema(
{vol.Required(ATTR_NAME): cv.string, vol.Required(ATTR_VALUE): cv.string}
)
SET_COMFORT_MODE_SCHEMA = vol.Schema({vol.Required(ATTR_NAME): cv.string})
SET_TEMPERATURE_MODE_SCHEMA = vol.Schema(
{vol.Required(ATTR_NAME): cv.string, vol.Required(ATTR_VALUE): cv.string}
)
async def async_setup_platform(
hass: HomeAssistant,
config: ConfigType,
async_add_entities: AddEntitiesCallback,
discovery_info: DiscoveryInfoType | None = None,
) -> None:
"""Set up the Ambiclimate device."""
async def async_setup_entry(
hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
) -> None:
"""Set up the Ambiclimate device from config entry."""
config = entry.data
websession = async_get_clientsession(hass)
store = Store[dict[str, Any]](hass, STORAGE_VERSION, STORAGE_KEY)
token_info = await store.async_load()
oauth = ambiclimate.AmbiclimateOAuth(
config[CONF_CLIENT_ID],
config[CONF_CLIENT_SECRET],
config["callback_url"],
websession,
)
try:
token_info = await oauth.refresh_access_token(token_info)
except ambiclimate.AmbiclimateOauthError:
token_info = None
if not token_info:
_LOGGER.error("Failed to refresh access token")
return
await store.async_save(token_info)
data_connection = ambiclimate.AmbiclimateConnection(
oauth, token_info=token_info, websession=websession
)
if not await data_connection.find_devices():
_LOGGER.error("No devices found")
return
tasks = [
asyncio.create_task(heater.update_device_info())
for heater in data_connection.get_devices()
]
await asyncio.wait(tasks)
async_add_entities(
(AmbiclimateEntity(heater, store) for heater in data_connection.get_devices()),
True,
)
async def send_comfort_feedback(service: ServiceCall) -> None:
"""Send comfort feedback."""
device_name = service.data[ATTR_NAME]
device = data_connection.find_device_by_room_name(device_name)
if device:
await device.set_comfort_feedback(service.data[ATTR_VALUE])
hass.services.async_register(
DOMAIN,
SERVICE_COMFORT_FEEDBACK,
send_comfort_feedback,
schema=SEND_COMFORT_FEEDBACK_SCHEMA,
)
async def set_comfort_mode(service: ServiceCall) -> None:
"""Set comfort mode."""
device_name = service.data[ATTR_NAME]
device = data_connection.find_device_by_room_name(device_name)
if device:
await device.set_comfort_mode()
hass.services.async_register(
DOMAIN, SERVICE_COMFORT_MODE, set_comfort_mode, schema=SET_COMFORT_MODE_SCHEMA
)
async def set_temperature_mode(service: ServiceCall) -> None:
"""Set temperature mode."""
device_name = service.data[ATTR_NAME]
device = data_connection.find_device_by_room_name(device_name)
if device:
await device.set_temperature_mode(service.data[ATTR_VALUE])
hass.services.async_register(
DOMAIN,
SERVICE_TEMPERATURE_MODE,
set_temperature_mode,
schema=SET_TEMPERATURE_MODE_SCHEMA,
)
class AmbiclimateEntity(ClimateEntity):
"""Representation of a Ambiclimate Thermostat device."""
_attr_temperature_unit = UnitOfTemperature.CELSIUS
_attr_target_temperature_step = 1
_attr_supported_features = (
ClimateEntityFeature.TARGET_TEMPERATURE
| ClimateEntityFeature.TURN_OFF
| ClimateEntityFeature.TURN_ON
)
_attr_hvac_modes = [HVACMode.HEAT, HVACMode.OFF]
_attr_has_entity_name = True
_attr_name = None
_enable_turn_on_off_backwards_compatibility = False
def __init__(self, heater: AmbiclimateDevice, store: Store[dict[str, Any]]) -> None:
"""Initialize the thermostat."""
self._heater = heater
self._store = store
self._attr_unique_id = heater.device_id
self._attr_device_info = DeviceInfo(
identifiers={(DOMAIN, self.unique_id)}, # type: ignore[arg-type]
manufacturer="Ambiclimate",
name=heater.name,
)
async def async_set_temperature(self, **kwargs: Any) -> None:
"""Set new target temperature."""
if (temperature := kwargs.get(ATTR_TEMPERATURE)) is None:
return
await self._heater.set_target_temperature(temperature)
async def async_set_hvac_mode(self, hvac_mode: HVACMode) -> None:
"""Set new target hvac mode."""
if hvac_mode == HVACMode.HEAT:
await self._heater.turn_on()
return
if hvac_mode == HVACMode.OFF:
await self._heater.turn_off()
async def async_update(self) -> None:
"""Retrieve latest state."""
try:
token_info = await self._heater.control.refresh_access_token()
except ambiclimate.AmbiclimateOauthError:
_LOGGER.error("Failed to refresh access token")
return
if token_info:
await self._store.async_save(token_info)
data = await self._heater.update_device()
self._attr_min_temp = self._heater.get_min_temp()
self._attr_max_temp = self._heater.get_max_temp()
self._attr_target_temperature = data.get("target_temperature")
self._attr_current_temperature = data.get("temperature")
self._attr_current_humidity = data.get("humidity")
self._attr_hvac_mode = (
HVACMode.HEAT if data.get("power", "").lower() == "on" else HVACMode.OFF
)

View file

@ -1,160 +0,0 @@
"""Config flow for Ambiclimate."""
import logging
from typing import Any
from aiohttp import web
import ambiclimate
from homeassistant.components.http import KEY_HASS, HomeAssistantView
from homeassistant.config_entries import ConfigFlow, ConfigFlowResult
from homeassistant.const import CONF_CLIENT_ID, CONF_CLIENT_SECRET
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.aiohttp_client import async_get_clientsession
from homeassistant.helpers.network import get_url
from homeassistant.helpers.storage import Store
from .const import (
AUTH_CALLBACK_NAME,
AUTH_CALLBACK_PATH,
DOMAIN,
STORAGE_KEY,
STORAGE_VERSION,
)
DATA_AMBICLIMATE_IMPL = "ambiclimate_flow_implementation"
_LOGGER = logging.getLogger(__name__)
@callback
def register_flow_implementation(
hass: HomeAssistant, client_id: str, client_secret: str
) -> None:
"""Register a ambiclimate implementation.
client_id: Client id.
client_secret: Client secret.
"""
hass.data.setdefault(DATA_AMBICLIMATE_IMPL, {})
hass.data[DATA_AMBICLIMATE_IMPL] = {
CONF_CLIENT_ID: client_id,
CONF_CLIENT_SECRET: client_secret,
}
class AmbiclimateFlowHandler(ConfigFlow, domain=DOMAIN):
"""Handle a config flow."""
VERSION = 1
def __init__(self) -> None:
"""Initialize flow."""
self._registered_view = False
self._oauth = None
async def async_step_user(
self, user_input: dict[str, Any] | None = None
) -> ConfigFlowResult:
"""Handle external yaml configuration."""
self._async_abort_entries_match()
config = self.hass.data.get(DATA_AMBICLIMATE_IMPL, {})
if not config:
_LOGGER.debug("No config")
return self.async_abort(reason="missing_configuration")
return await self.async_step_auth()
async def async_step_auth(
self, user_input: dict[str, Any] | None = None
) -> ConfigFlowResult:
"""Handle a flow start."""
self._async_abort_entries_match()
errors = {}
if user_input is not None:
errors["base"] = "follow_link"
if not self._registered_view:
self._generate_view()
return self.async_show_form(
step_id="auth",
description_placeholders={
"authorization_url": await self._get_authorize_url(),
"cb_url": self._cb_url(),
},
errors=errors,
)
async def async_step_code(self, code: str | None = None) -> ConfigFlowResult:
"""Received code for authentication."""
self._async_abort_entries_match()
if await self._get_token_info(code) is None:
return self.async_abort(reason="access_token")
config = self.hass.data[DATA_AMBICLIMATE_IMPL].copy()
config["callback_url"] = self._cb_url()
return self.async_create_entry(title="Ambiclimate", data=config)
async def _get_token_info(self, code: str | None) -> dict[str, Any] | None:
oauth = self._generate_oauth()
try:
token_info = await oauth.get_access_token(code)
except ambiclimate.AmbiclimateOauthError:
_LOGGER.exception("Failed to get access token")
return None
store = Store[dict[str, Any]](self.hass, STORAGE_VERSION, STORAGE_KEY)
await store.async_save(token_info)
return token_info # type: ignore[no-any-return]
def _generate_view(self) -> None:
self.hass.http.register_view(AmbiclimateAuthCallbackView())
self._registered_view = True
def _generate_oauth(self) -> ambiclimate.AmbiclimateOAuth:
config = self.hass.data[DATA_AMBICLIMATE_IMPL]
clientsession = async_get_clientsession(self.hass)
callback_url = self._cb_url()
return ambiclimate.AmbiclimateOAuth(
config.get(CONF_CLIENT_ID),
config.get(CONF_CLIENT_SECRET),
callback_url,
clientsession,
)
def _cb_url(self) -> str:
return f"{get_url(self.hass, prefer_external=True)}{AUTH_CALLBACK_PATH}"
async def _get_authorize_url(self) -> str:
oauth = self._generate_oauth()
return oauth.get_authorize_url() # type: ignore[no-any-return]
class AmbiclimateAuthCallbackView(HomeAssistantView):
"""Ambiclimate Authorization Callback View."""
requires_auth = False
url = AUTH_CALLBACK_PATH
name = AUTH_CALLBACK_NAME
async def get(self, request: web.Request) -> str:
"""Receive authorization token."""
if (code := request.query.get("code")) is None:
return "No code"
hass = request.app[KEY_HASS]
hass.async_create_task(
hass.config_entries.flow.async_init(
DOMAIN, context={"source": "code"}, data=code
)
)
return "OK!"

View file

@ -1,15 +0,0 @@
"""Constants used by the Ambiclimate component."""
DOMAIN = "ambiclimate"
ATTR_VALUE = "value"
SERVICE_COMFORT_FEEDBACK = "send_comfort_feedback"
SERVICE_COMFORT_MODE = "set_comfort_mode"
SERVICE_TEMPERATURE_MODE = "set_temperature_mode"
STORAGE_KEY = "ambiclimate_auth"
STORAGE_VERSION = 1
AUTH_CALLBACK_NAME = "api:ambiclimate"
AUTH_CALLBACK_PATH = "/api/ambiclimate"

View file

@ -1,7 +0,0 @@
{
"services": {
"set_comfort_mode": "mdi:auto-mode",
"send_comfort_feedback": "mdi:thermometer-checked",
"set_temperature_mode": "mdi:thermometer"
}
}

View file

@ -1,11 +0,0 @@
{
"domain": "ambiclimate",
"name": "Ambiclimate",
"codeowners": ["@danielhiversen"],
"config_flow": true,
"dependencies": ["http"],
"documentation": "https://www.home-assistant.io/integrations/ambiclimate",
"iot_class": "cloud_polling",
"loggers": ["ambiclimate"],
"requirements": ["Ambiclimate==0.2.1"]
}

View file

@ -1,35 +0,0 @@
# Describes the format for available services for ambiclimate
set_comfort_mode:
fields:
name:
required: true
example: Bedroom
selector:
text:
send_comfort_feedback:
fields:
name:
required: true
example: Bedroom
selector:
text:
value:
required: true
example: bit_warm
selector:
text:
set_temperature_mode:
fields:
name:
required: true
example: Bedroom
selector:
text:
value:
required: true
example: 22
selector:
text:

View file

@ -1,68 +0,0 @@
{
"config": {
"step": {
"auth": {
"title": "Authenticate Ambiclimate",
"description": "Please follow this [link]({authorization_url}) and **Allow** access to your Ambiclimate account, then come back and press **Submit** below.\n(Make sure the specified callback URL is {cb_url})"
}
},
"create_entry": {
"default": "[%key:common::config_flow::create_entry::authenticated%]"
},
"error": {
"no_token": "Not authenticated with Ambiclimate",
"follow_link": "Please follow the link and authenticate before pressing Submit"
},
"abort": {
"already_configured": "[%key:common::config_flow::abort::already_configured_account%]",
"missing_configuration": "[%key:common::config_flow::abort::oauth2_missing_configuration%]",
"access_token": "Unknown error generating an access token."
}
},
"issues": {
"integration_removed": {
"title": "The Ambiclimate integration has been deprecated and will be removed",
"description": "All Ambiclimate services will be terminated, effective March 31, 2024, as Ambi Labs winds down business operations, and the Ambiclimate integration will be removed from Home Assistant.\n\nTo resolve this issue, please remove the integration entries from your Home Assistant setup. [Click here to see your existing Logi Circle integration entries]({entries})."
}
},
"services": {
"set_comfort_mode": {
"name": "Set comfort mode",
"description": "Enables comfort mode on your AC.",
"fields": {
"name": {
"name": "Device name",
"description": "String with device name."
}
}
},
"send_comfort_feedback": {
"name": "Send comfort feedback",
"description": "Sends feedback for comfort mode.",
"fields": {
"name": {
"name": "[%key:component::ambiclimate::services::set_comfort_mode::fields::name::name%]",
"description": "[%key:component::ambiclimate::services::set_comfort_mode::fields::name::description%]"
},
"value": {
"name": "Comfort value",
"description": "Send any of the following comfort values: too_hot, too_warm, bit_warm, comfortable, bit_cold, too_cold, freezing."
}
}
},
"set_temperature_mode": {
"name": "Set temperature mode",
"description": "Enables temperature mode on your AC.",
"fields": {
"name": {
"name": "[%key:component::ambiclimate::services::set_comfort_mode::fields::name::name%]",
"description": "[%key:component::ambiclimate::services::set_comfort_mode::fields::name::description%]"
},
"value": {
"name": "Temperature",
"description": "Target value in celsius."
}
}
}
}
}

View file

@ -41,7 +41,6 @@ FLOWS = {
"aladdin_connect",
"alarmdecoder",
"amberelectric",
"ambiclimate",
"ambient_network",
"ambient_station",
"analytics_insights",

View file

@ -238,12 +238,6 @@
"config_flow": true,
"iot_class": "cloud_polling"
},
"ambiclimate": {
"name": "Ambiclimate",
"integration_type": "hub",
"config_flow": true,
"iot_class": "cloud_polling"
},
"ambient_network": {
"name": "Ambient Weather Network",
"integration_type": "service",

View file

@ -411,16 +411,6 @@ disallow_untyped_defs = true
warn_return_any = true
warn_unreachable = true
[mypy-homeassistant.components.ambiclimate.*]
check_untyped_defs = true
disallow_incomplete_defs = true
disallow_subclassing_any = true
disallow_untyped_calls = true
disallow_untyped_decorators = true
disallow_untyped_defs = true
warn_return_any = true
warn_unreachable = true
[mypy-homeassistant.components.ambient_network.*]
check_untyped_defs = true
disallow_incomplete_defs = true

View file

@ -15,9 +15,6 @@ AIOSomecomfort==0.0.25
# homeassistant.components.adax
Adax-local==0.1.5
# homeassistant.components.ambiclimate
Ambiclimate==0.2.1
# homeassistant.components.blinksticklight
BlinkStick==1.2.0

View file

@ -15,9 +15,6 @@ AIOSomecomfort==0.0.25
# homeassistant.components.adax
Adax-local==0.1.5
# homeassistant.components.ambiclimate
Ambiclimate==0.2.1
# homeassistant.components.doorbird
DoorBirdPy==2.1.0

View file

@ -1 +0,0 @@
"""Tests for the Ambiclimate component."""

View file

@ -1,140 +0,0 @@
"""Tests for the Ambiclimate config flow."""
from unittest.mock import AsyncMock, patch
import ambiclimate
import pytest
from homeassistant import config_entries
from homeassistant.components.ambiclimate import config_flow
from homeassistant.components.http import KEY_HASS
from homeassistant.config import async_process_ha_core_config
from homeassistant.const import CONF_CLIENT_ID, CONF_CLIENT_SECRET
from homeassistant.core import HomeAssistant
from homeassistant.data_entry_flow import AbortFlow, FlowResultType
from homeassistant.setup import async_setup_component
from homeassistant.util import aiohttp
from tests.common import MockConfigEntry
async def init_config_flow(hass):
"""Init a configuration flow."""
await async_process_ha_core_config(
hass,
{"external_url": "https://example.com"},
)
await async_setup_component(hass, "http", {})
config_flow.register_flow_implementation(hass, "id", "secret")
flow = config_flow.AmbiclimateFlowHandler()
flow.hass = hass
return flow
async def test_abort_if_no_implementation_registered(hass: HomeAssistant) -> None:
"""Test we abort if no implementation is registered."""
flow = config_flow.AmbiclimateFlowHandler()
flow.hass = hass
result = await flow.async_step_user()
assert result["type"] is FlowResultType.ABORT
assert result["reason"] == "missing_configuration"
async def test_abort_if_already_setup(hass: HomeAssistant) -> None:
"""Test we abort if Ambiclimate is already setup."""
flow = await init_config_flow(hass)
MockConfigEntry(domain=config_flow.DOMAIN).add_to_hass(hass)
result = await hass.config_entries.flow.async_init(
config_flow.DOMAIN,
context={"source": config_entries.SOURCE_USER},
)
assert result["type"] is FlowResultType.ABORT
assert result["reason"] == "already_configured"
with pytest.raises(AbortFlow):
result = await flow.async_step_code()
assert result["type"] is FlowResultType.ABORT
assert result["reason"] == "already_configured"
async def test_full_flow_implementation(hass: HomeAssistant) -> None:
"""Test registering an implementation and finishing flow works."""
config_flow.register_flow_implementation(hass, None, None)
flow = await init_config_flow(hass)
result = await flow.async_step_user()
assert result["type"] is FlowResultType.FORM
assert result["step_id"] == "auth"
assert (
result["description_placeholders"]["cb_url"]
== "https://example.com/api/ambiclimate"
)
url = result["description_placeholders"]["authorization_url"]
assert "https://api.ambiclimate.com/oauth2/authorize" in url
assert "client_id=id" in url
assert "response_type=code" in url
assert "redirect_uri=https%3A%2F%2Fexample.com%2Fapi%2Fambiclimate" in url
with patch("ambiclimate.AmbiclimateOAuth.get_access_token", return_value="test"):
result = await flow.async_step_code("123ABC")
assert result["type"] is FlowResultType.CREATE_ENTRY
assert result["title"] == "Ambiclimate"
assert result["data"]["callback_url"] == "https://example.com/api/ambiclimate"
assert result["data"][CONF_CLIENT_SECRET] == "secret"
assert result["data"][CONF_CLIENT_ID] == "id"
with patch("ambiclimate.AmbiclimateOAuth.get_access_token", return_value=None):
result = await flow.async_step_code("123ABC")
assert result["type"] is FlowResultType.ABORT
with patch(
"ambiclimate.AmbiclimateOAuth.get_access_token",
side_effect=ambiclimate.AmbiclimateOauthError(),
):
result = await flow.async_step_code("123ABC")
assert result["type"] is FlowResultType.ABORT
async def test_abort_invalid_code(hass: HomeAssistant) -> None:
"""Test if no code is given to step_code."""
config_flow.register_flow_implementation(hass, None, None)
flow = await init_config_flow(hass)
with patch("ambiclimate.AmbiclimateOAuth.get_access_token", return_value=None):
result = await flow.async_step_code("invalid")
assert result["type"] is FlowResultType.ABORT
assert result["reason"] == "access_token"
async def test_already_setup(hass: HomeAssistant) -> None:
"""Test when already setup."""
MockConfigEntry(domain=config_flow.DOMAIN).add_to_hass(hass)
result = await hass.config_entries.flow.async_init(
config_flow.DOMAIN,
context={"source": config_entries.SOURCE_USER},
)
assert result["type"] is FlowResultType.ABORT
assert result["reason"] == "already_configured"
async def test_view(hass: HomeAssistant) -> None:
"""Test view."""
hass.config_entries.flow.async_init = AsyncMock()
request = aiohttp.MockRequest(
b"", query_string="code=test_code", mock_source="test"
)
request.app = {KEY_HASS: hass}
view = config_flow.AmbiclimateAuthCallbackView()
assert await view.get(request) == "OK!"
request = aiohttp.MockRequest(b"", query_string="", mock_source="test")
request.app = {KEY_HASS: hass}
view = config_flow.AmbiclimateAuthCallbackView()
assert await view.get(request) == "No code"

View file

@ -1,44 +0,0 @@
"""Tests for the Ambiclimate integration."""
from unittest.mock import patch
import pytest
from homeassistant.components.ambiclimate import DOMAIN
from homeassistant.config_entries import ConfigEntryState
from homeassistant.core import HomeAssistant
from homeassistant.helpers import issue_registry as ir
from tests.common import MockConfigEntry
@pytest.fixture(name="disable_platforms")
async def disable_platforms_fixture(hass):
"""Disable ambiclimate platforms."""
with patch("homeassistant.components.ambiclimate.PLATFORMS", []):
yield
async def test_repair_issue(
hass: HomeAssistant,
issue_registry: ir.IssueRegistry,
disable_platforms,
) -> None:
"""Test the Ambiclimate configuration entry loading handles the repair."""
config_entry = MockConfigEntry(
title="Example 1",
domain=DOMAIN,
)
config_entry.add_to_hass(hass)
await hass.config_entries.async_setup(config_entry.entry_id)
await hass.async_block_till_done()
assert config_entry.state is ConfigEntryState.LOADED
assert issue_registry.async_get_issue(DOMAIN, DOMAIN)
# Remove the entry
await hass.config_entries.async_remove(config_entry.entry_id)
await hass.async_block_till_done()
# Ambiclimate does not implement unload
assert config_entry.state is ConfigEntryState.FAILED_UNLOAD
assert issue_registry.async_get_issue(DOMAIN, DOMAIN)