Remove JuiceNet integration (#111477)

* Remove JuiceNet integration

* Adjust issue

* Add test

* Fix stale DOMAIN constant
This commit is contained in:
Erik Montnemery 2024-02-26 20:08:36 +01:00 committed by GitHub
parent a55c56a207
commit 730fe760cf
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
19 changed files with 80 additions and 669 deletions

View File

@ -638,12 +638,6 @@ omit =
homeassistant/components/izone/climate.py
homeassistant/components/izone/discovery.py
homeassistant/components/joaoapps_join/*
homeassistant/components/juicenet/__init__.py
homeassistant/components/juicenet/device.py
homeassistant/components/juicenet/entity.py
homeassistant/components/juicenet/number.py
homeassistant/components/juicenet/sensor.py
homeassistant/components/juicenet/switch.py
homeassistant/components/justnimbus/coordinator.py
homeassistant/components/justnimbus/entity.py
homeassistant/components/justnimbus/sensor.py

View File

@ -669,8 +669,6 @@ build.json @home-assistant/supervisor
/tests/components/jellyfin/ @j-stienstra @ctalkington
/homeassistant/components/jewish_calendar/ @tsvi
/tests/components/jewish_calendar/ @tsvi
/homeassistant/components/juicenet/ @jesserockz
/tests/components/juicenet/ @jesserockz
/homeassistant/components/justnimbus/ @kvanzuijlen
/tests/components/justnimbus/ @kvanzuijlen
/homeassistant/components/jvc_projector/ @SteveEasley @msavazzi

View File

@ -1,107 +1,37 @@
"""The JuiceNet integration."""
from datetime import timedelta
import logging
from __future__ import annotations
import aiohttp
from pyjuicenet import Api, TokenError
import voluptuous as vol
from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry
from homeassistant.const import CONF_ACCESS_TOKEN, Platform
from homeassistant.config_entries import ConfigEntry, ConfigEntryState
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ConfigEntryNotReady
from homeassistant.helpers import config_validation as cv
from homeassistant.helpers.aiohttp_client import async_get_clientsession
from homeassistant.helpers.typing import ConfigType
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
from homeassistant.helpers import issue_registry as ir
from .const import DOMAIN, JUICENET_API, JUICENET_COORDINATOR
from .device import JuiceNetApi
_LOGGER = logging.getLogger(__name__)
PLATFORMS = [Platform.NUMBER, Platform.SENSOR, Platform.SWITCH]
CONFIG_SCHEMA = vol.Schema(
vol.All(
cv.deprecated(DOMAIN),
{DOMAIN: vol.Schema({vol.Required(CONF_ACCESS_TOKEN): cv.string})},
),
extra=vol.ALLOW_EXTRA,
)
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
"""Set up the JuiceNet component."""
conf = config.get(DOMAIN)
hass.data.setdefault(DOMAIN, {})
if not conf:
return True
hass.async_create_task(
hass.config_entries.flow.async_init(
DOMAIN, context={"source": SOURCE_IMPORT}, data=conf
)
)
return True
DOMAIN = "juicenet"
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Set up JuiceNet from a config entry."""
config = entry.data
session = async_get_clientsession(hass)
access_token = config[CONF_ACCESS_TOKEN]
api = Api(access_token, session)
juicenet = JuiceNetApi(api)
try:
await juicenet.setup()
except TokenError as error:
_LOGGER.error("JuiceNet Error %s", error)
return False
except aiohttp.ClientError as error:
_LOGGER.error("Could not reach the JuiceNet API %s", error)
raise ConfigEntryNotReady from error
if not juicenet.devices:
_LOGGER.error("No JuiceNet devices found for this account")
return False
_LOGGER.info("%d JuiceNet device(s) found", len(juicenet.devices))
async def async_update_data():
"""Update all device states from the JuiceNet API."""
for device in juicenet.devices:
await device.update_state(True)
return True
coordinator = DataUpdateCoordinator(
ir.async_create_issue(
hass,
_LOGGER,
name="JuiceNet",
update_method=async_update_data,
update_interval=timedelta(seconds=30),
DOMAIN,
DOMAIN,
is_fixable=False,
severity=ir.IssueSeverity.ERROR,
translation_key="integration_removed",
translation_placeholders={
"entries": "/config/integrations/integration/juicenet",
},
)
await coordinator.async_config_entry_first_refresh()
hass.data[DOMAIN][entry.entry_id] = {
JUICENET_API: juicenet,
JUICENET_COORDINATOR: coordinator,
}
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
return True
async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Unload a config entry."""
unload_ok = await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
if unload_ok:
hass.data[DOMAIN].pop(entry.entry_id)
return unload_ok
if all(
config_entry.state is ConfigEntryState.NOT_LOADED
for config_entry in hass.config_entries.async_entries(DOMAIN)
if config_entry.entry_id != entry.entry_id
):
ir.async_delete_issue(hass, DOMAIN, DOMAIN)
return True

View File

@ -1,77 +1,11 @@
"""Config flow for JuiceNet integration."""
import logging
import aiohttp
from pyjuicenet import Api, TokenError
import voluptuous as vol
from homeassistant import config_entries
from homeassistant import config_entries, core, exceptions
from homeassistant.const import CONF_ACCESS_TOKEN
from homeassistant.helpers.aiohttp_client import async_get_clientsession
from .const import DOMAIN
_LOGGER = logging.getLogger(__name__)
DATA_SCHEMA = vol.Schema({vol.Required(CONF_ACCESS_TOKEN): str})
async def validate_input(hass: core.HomeAssistant, data):
"""Validate the user input allows us to connect.
Data has the keys from DATA_SCHEMA with values provided by the user.
"""
session = async_get_clientsession(hass)
juicenet = Api(data[CONF_ACCESS_TOKEN], session)
try:
await juicenet.get_devices()
except TokenError as error:
_LOGGER.error("Token Error %s", error)
raise InvalidAuth from error
except aiohttp.ClientError as error:
_LOGGER.error("Error connecting %s", error)
raise CannotConnect from error
# Return info that you want to store in the config entry.
return {"title": "JuiceNet"}
from . import DOMAIN
class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
"""Handle a config flow for JuiceNet."""
VERSION = 1
async def async_step_user(self, user_input=None):
"""Handle the initial step."""
errors = {}
if user_input is not None:
await self.async_set_unique_id(user_input[CONF_ACCESS_TOKEN])
self._abort_if_unique_id_configured()
try:
info = await validate_input(self.hass, user_input)
return self.async_create_entry(title=info["title"], data=user_input)
except CannotConnect:
errors["base"] = "cannot_connect"
except InvalidAuth:
errors["base"] = "invalid_auth"
except Exception: # pylint: disable=broad-except
_LOGGER.exception("Unexpected exception")
errors["base"] = "unknown"
return self.async_show_form(
step_id="user", data_schema=DATA_SCHEMA, errors=errors
)
async def async_step_import(self, user_input):
"""Handle import."""
return await self.async_step_user(user_input)
class CannotConnect(exceptions.HomeAssistantError):
"""Error to indicate we cannot connect."""
class InvalidAuth(exceptions.HomeAssistantError):
"""Error to indicate there is invalid auth."""

View File

@ -1,6 +0,0 @@
"""Constants used by the JuiceNet component."""
DOMAIN = "juicenet"
JUICENET_API = "juicenet_api"
JUICENET_COORDINATOR = "juicenet_coordinator"

View File

@ -1,19 +0,0 @@
"""Adapter to wrap the pyjuicenet api for home assistant."""
class JuiceNetApi:
"""Represent a connection to JuiceNet."""
def __init__(self, api):
"""Create an object from the provided API instance."""
self.api = api
self._devices = []
async def setup(self):
"""JuiceNet device setup.""" # noqa: D403
self._devices = await self.api.get_devices()
@property
def devices(self) -> list:
"""Get a list of devices managed by this account."""
return self._devices

View File

@ -1,34 +0,0 @@
"""Adapter to wrap the pyjuicenet api for home assistant."""
from pyjuicenet import Charger
from homeassistant.helpers.device_registry import DeviceInfo
from homeassistant.helpers.update_coordinator import (
CoordinatorEntity,
DataUpdateCoordinator,
)
from .const import DOMAIN
class JuiceNetDevice(CoordinatorEntity):
"""Represent a base JuiceNet device."""
_attr_has_entity_name = True
def __init__(
self, device: Charger, key: str, coordinator: DataUpdateCoordinator
) -> None:
"""Initialise the sensor."""
super().__init__(coordinator)
self.device = device
self.key = key
self._attr_unique_id = f"{device.id}-{key}"
self._attr_device_info = DeviceInfo(
configuration_url=(
f"https://home.juice.net/Portal/Details?unitID={device.id}"
),
identifiers={(DOMAIN, device.id)},
manufacturer="JuiceNet",
name=device.name,
)

View File

@ -1,10 +1,9 @@
{
"domain": "juicenet",
"name": "JuiceNet",
"codeowners": ["@jesserockz"],
"config_flow": true,
"codeowners": [],
"documentation": "https://www.home-assistant.io/integrations/juicenet",
"integration_type": "system",
"iot_class": "cloud_polling",
"loggers": ["pyjuicenet"],
"requirements": ["python-juicenet==1.1.0"]
"requirements": []
}

View File

@ -1,99 +0,0 @@
"""Support for controlling juicenet/juicepoint/juicebox based EVSE numbers."""
from __future__ import annotations
from dataclasses import dataclass
from pyjuicenet import Api, Charger
from homeassistant.components.number import (
DEFAULT_MAX_VALUE,
NumberEntity,
NumberEntityDescription,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
from .const import DOMAIN, JUICENET_API, JUICENET_COORDINATOR
from .entity import JuiceNetDevice
@dataclass(frozen=True)
class JuiceNetNumberEntityDescriptionMixin:
"""Mixin for required keys."""
setter_key: str
@dataclass(frozen=True)
class JuiceNetNumberEntityDescription(
NumberEntityDescription, JuiceNetNumberEntityDescriptionMixin
):
"""An entity description for a JuiceNetNumber."""
native_max_value_key: str | None = None
NUMBER_TYPES: tuple[JuiceNetNumberEntityDescription, ...] = (
JuiceNetNumberEntityDescription(
translation_key="amperage_limit",
key="current_charging_amperage_limit",
native_min_value=6,
native_max_value_key="max_charging_amperage",
native_step=1,
setter_key="set_charging_amperage_limit",
),
)
async def async_setup_entry(
hass: HomeAssistant,
config_entry: ConfigEntry,
async_add_entities: AddEntitiesCallback,
) -> None:
"""Set up the JuiceNet Numbers."""
juicenet_data = hass.data[DOMAIN][config_entry.entry_id]
api: Api = juicenet_data[JUICENET_API]
coordinator = juicenet_data[JUICENET_COORDINATOR]
entities = [
JuiceNetNumber(device, description, coordinator)
for device in api.devices
for description in NUMBER_TYPES
]
async_add_entities(entities)
class JuiceNetNumber(JuiceNetDevice, NumberEntity):
"""Implementation of a JuiceNet number."""
entity_description: JuiceNetNumberEntityDescription
def __init__(
self,
device: Charger,
description: JuiceNetNumberEntityDescription,
coordinator: DataUpdateCoordinator,
) -> None:
"""Initialise the number."""
super().__init__(device, description.key, coordinator)
self.entity_description = description
@property
def native_value(self) -> float | None:
"""Return the value of the entity."""
return getattr(self.device, self.entity_description.key, None)
@property
def native_max_value(self) -> float:
"""Return the maximum value."""
if self.entity_description.native_max_value_key is not None:
return getattr(self.device, self.entity_description.native_max_value_key)
if self.entity_description.native_max_value is not None:
return self.entity_description.native_max_value
return DEFAULT_MAX_VALUE
async def async_set_native_value(self, value: float) -> None:
"""Update the current value."""
await getattr(self.device, self.entity_description.setter_key)(value)

View File

@ -1,116 +0,0 @@
"""Support for monitoring juicenet/juicepoint/juicebox based EVSE sensors."""
from __future__ import annotations
from homeassistant.components.sensor import (
SensorDeviceClass,
SensorEntity,
SensorEntityDescription,
SensorStateClass,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import (
UnitOfElectricCurrent,
UnitOfElectricPotential,
UnitOfEnergy,
UnitOfPower,
UnitOfTemperature,
UnitOfTime,
)
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from .const import DOMAIN, JUICENET_API, JUICENET_COORDINATOR
from .entity import JuiceNetDevice
SENSOR_TYPES: tuple[SensorEntityDescription, ...] = (
SensorEntityDescription(
key="status",
name="Charging Status",
),
SensorEntityDescription(
key="temperature",
native_unit_of_measurement=UnitOfTemperature.CELSIUS,
device_class=SensorDeviceClass.TEMPERATURE,
state_class=SensorStateClass.MEASUREMENT,
),
SensorEntityDescription(
key="voltage",
native_unit_of_measurement=UnitOfElectricPotential.VOLT,
device_class=SensorDeviceClass.VOLTAGE,
),
SensorEntityDescription(
key="amps",
native_unit_of_measurement=UnitOfElectricCurrent.AMPERE,
device_class=SensorDeviceClass.CURRENT,
state_class=SensorStateClass.MEASUREMENT,
),
SensorEntityDescription(
key="watts",
native_unit_of_measurement=UnitOfPower.WATT,
device_class=SensorDeviceClass.POWER,
state_class=SensorStateClass.MEASUREMENT,
),
SensorEntityDescription(
key="charge_time",
translation_key="charge_time",
native_unit_of_measurement=UnitOfTime.SECONDS,
icon="mdi:timer-outline",
),
SensorEntityDescription(
key="energy_added",
translation_key="energy_added",
native_unit_of_measurement=UnitOfEnergy.WATT_HOUR,
device_class=SensorDeviceClass.ENERGY,
state_class=SensorStateClass.TOTAL_INCREASING,
),
)
async def async_setup_entry(
hass: HomeAssistant,
config_entry: ConfigEntry,
async_add_entities: AddEntitiesCallback,
) -> None:
"""Set up the JuiceNet Sensors."""
juicenet_data = hass.data[DOMAIN][config_entry.entry_id]
api = juicenet_data[JUICENET_API]
coordinator = juicenet_data[JUICENET_COORDINATOR]
entities = [
JuiceNetSensorDevice(device, coordinator, description)
for device in api.devices
for description in SENSOR_TYPES
]
async_add_entities(entities)
class JuiceNetSensorDevice(JuiceNetDevice, SensorEntity):
"""Implementation of a JuiceNet sensor."""
def __init__(
self, device, coordinator, description: SensorEntityDescription
) -> None:
"""Initialise the sensor."""
super().__init__(device, description.key, coordinator)
self.entity_description = description
@property
def icon(self):
"""Return the icon of the sensor."""
icon = None
if self.entity_description.key == "status":
status = self.device.status
if status == "standby":
icon = "mdi:power-plug-off"
elif status == "plugged":
icon = "mdi:power-plug"
elif status == "charging":
icon = "mdi:battery-positive"
else:
icon = self.entity_description.icon
return icon
@property
def native_value(self):
"""Return the state."""
return getattr(self.device, self.entity_description.key, None)

View File

@ -1,41 +1,8 @@
{
"config": {
"abort": {
"already_configured": "[%key:common::config_flow::abort::already_configured_account%]"
},
"error": {
"cannot_connect": "[%key:common::config_flow::error::cannot_connect%]",
"invalid_auth": "[%key:common::config_flow::error::invalid_auth%]",
"unknown": "[%key:common::config_flow::error::unknown%]"
},
"step": {
"user": {
"data": {
"api_token": "[%key:common::config_flow::data::api_token%]"
},
"description": "You will need the API Token from https://home.juice.net/Manage.",
"title": "Connect to JuiceNet"
}
}
},
"entity": {
"number": {
"amperage_limit": {
"name": "Amperage limit"
}
},
"sensor": {
"charge_time": {
"name": "Charge time"
},
"energy_added": {
"name": "Energy added"
}
},
"switch": {
"charge_now": {
"name": "Charge now"
}
"issues": {
"integration_removed": {
"title": "The JuiceNet integration has been removed",
"description": "Enel X has dropped support for JuiceNet in favor of JuicePass, and the JuiceNet integration has been removed from Home Assistant as it was no longer working.\n\nTo resolve this issue, please remove the (now defunct) integration entries from your Home Assistant setup. [Click here to see your existing JuiceNet integration entries]({entries})."
}
}
}

View File

@ -1,49 +0,0 @@
"""Support for monitoring juicenet/juicepoint/juicebox based EVSE switches."""
from typing import Any
from homeassistant.components.switch import SwitchEntity
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from .const import DOMAIN, JUICENET_API, JUICENET_COORDINATOR
from .entity import JuiceNetDevice
async def async_setup_entry(
hass: HomeAssistant,
config_entry: ConfigEntry,
async_add_entities: AddEntitiesCallback,
) -> None:
"""Set up the JuiceNet switches."""
entities = []
juicenet_data = hass.data[DOMAIN][config_entry.entry_id]
api = juicenet_data[JUICENET_API]
coordinator = juicenet_data[JUICENET_COORDINATOR]
for device in api.devices:
entities.append(JuiceNetChargeNowSwitch(device, coordinator))
async_add_entities(entities)
class JuiceNetChargeNowSwitch(JuiceNetDevice, SwitchEntity):
"""Implementation of a JuiceNet switch."""
_attr_translation_key = "charge_now"
def __init__(self, device, coordinator):
"""Initialise the switch."""
super().__init__(device, "charge_now", coordinator)
@property
def is_on(self):
"""Return true if switch is on."""
return self.device.override_time != 0
async def async_turn_on(self, **kwargs: Any) -> None:
"""Charge now."""
await self.device.set_override(True)
async def async_turn_off(self, **kwargs: Any) -> None:
"""Don't charge now."""
await self.device.set_override(False)

View File

@ -255,7 +255,6 @@ FLOWS = {
"isy994",
"izone",
"jellyfin",
"juicenet",
"justnimbus",
"jvc_projector",
"kaleidescape",

View File

@ -2911,12 +2911,6 @@
"config_flow": false,
"iot_class": "cloud_push"
},
"juicenet": {
"name": "JuiceNet",
"integration_type": "hub",
"config_flow": true,
"iot_class": "cloud_polling"
},
"justnimbus": {
"name": "JustNimbus",
"integration_type": "hub",

View File

@ -2244,9 +2244,6 @@ python-izone==1.2.9
# homeassistant.components.joaoapps_join
python-join-api==0.0.9
# homeassistant.components.juicenet
python-juicenet==1.1.0
# homeassistant.components.tplink
python-kasa[speedups]==0.6.2.1

View File

@ -1720,9 +1720,6 @@ python-homewizard-energy==4.3.1
# homeassistant.components.izone
python-izone==1.2.9
# homeassistant.components.juicenet
python-juicenet==1.1.0
# homeassistant.components.tplink
python-kasa[speedups]==0.6.2.1

View File

@ -33,7 +33,6 @@ IGNORE_VIOLATIONS = {
"blink",
"ezviz",
"hdmi_cec",
"juicenet",
"lupusec",
"rainbird",
"slide",

View File

@ -1,124 +0,0 @@
"""Test the JuiceNet config flow."""
from unittest.mock import MagicMock, patch
import aiohttp
from pyjuicenet import TokenError
from homeassistant import config_entries
from homeassistant.components.juicenet.const import DOMAIN
from homeassistant.const import CONF_ACCESS_TOKEN
from homeassistant.core import HomeAssistant
def _mock_juicenet_return_value(get_devices=None):
juicenet_mock = MagicMock()
type(juicenet_mock).get_devices = MagicMock(return_value=get_devices)
return juicenet_mock
async def test_form(hass: HomeAssistant) -> None:
"""Test we get the form."""
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": config_entries.SOURCE_USER}
)
assert result["type"] == "form"
assert result["errors"] == {}
with patch(
"homeassistant.components.juicenet.config_flow.Api.get_devices",
return_value=MagicMock(),
), patch(
"homeassistant.components.juicenet.async_setup", return_value=True
) as mock_setup, patch(
"homeassistant.components.juicenet.async_setup_entry", return_value=True
) as mock_setup_entry:
result2 = await hass.config_entries.flow.async_configure(
result["flow_id"], {CONF_ACCESS_TOKEN: "access_token"}
)
await hass.async_block_till_done()
assert result2["type"] == "create_entry"
assert result2["title"] == "JuiceNet"
assert result2["data"] == {CONF_ACCESS_TOKEN: "access_token"}
assert len(mock_setup.mock_calls) == 1
assert len(mock_setup_entry.mock_calls) == 1
async def test_form_invalid_auth(hass: HomeAssistant) -> None:
"""Test we handle invalid auth."""
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": config_entries.SOURCE_USER}
)
with patch(
"homeassistant.components.juicenet.config_flow.Api.get_devices",
side_effect=TokenError,
):
result2 = await hass.config_entries.flow.async_configure(
result["flow_id"], {CONF_ACCESS_TOKEN: "access_token"}
)
assert result2["type"] == "form"
assert result2["errors"] == {"base": "invalid_auth"}
async def test_form_cannot_connect(hass: HomeAssistant) -> None:
"""Test we handle cannot connect error."""
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": config_entries.SOURCE_USER}
)
with patch(
"homeassistant.components.juicenet.config_flow.Api.get_devices",
side_effect=aiohttp.ClientError,
):
result2 = await hass.config_entries.flow.async_configure(
result["flow_id"], {CONF_ACCESS_TOKEN: "access_token"}
)
assert result2["type"] == "form"
assert result2["errors"] == {"base": "cannot_connect"}
async def test_form_catch_unknown_errors(hass: HomeAssistant) -> None:
"""Test we handle cannot connect error."""
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": config_entries.SOURCE_USER}
)
with patch(
"homeassistant.components.juicenet.config_flow.Api.get_devices",
side_effect=Exception,
):
result2 = await hass.config_entries.flow.async_configure(
result["flow_id"], {CONF_ACCESS_TOKEN: "access_token"}
)
assert result2["type"] == "form"
assert result2["errors"] == {"base": "unknown"}
async def test_import(hass: HomeAssistant) -> None:
"""Test that import works as expected."""
with patch(
"homeassistant.components.juicenet.config_flow.Api.get_devices",
return_value=MagicMock(),
), patch(
"homeassistant.components.juicenet.async_setup", return_value=True
) as mock_setup, patch(
"homeassistant.components.juicenet.async_setup_entry", return_value=True
) as mock_setup_entry:
result = await hass.config_entries.flow.async_init(
DOMAIN,
context={"source": config_entries.SOURCE_IMPORT},
data={CONF_ACCESS_TOKEN: "access_token"},
)
await hass.async_block_till_done()
assert result["type"] == "create_entry"
assert result["title"] == "JuiceNet"
assert result["data"] == {CONF_ACCESS_TOKEN: "access_token"}
assert len(mock_setup.mock_calls) == 1
assert len(mock_setup_entry.mock_calls) == 1

View File

@ -0,0 +1,50 @@
"""Tests for the JuiceNet component."""
from homeassistant.components.juicenet 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
async def test_juicenet_repair_issue(
hass: HomeAssistant, issue_registry: ir.IssueRegistry
) -> None:
"""Test the JuiceNet configuration entry loading/unloading handles the repair."""
config_entry_1 = MockConfigEntry(
title="Example 1",
domain=DOMAIN,
)
config_entry_1.add_to_hass(hass)
await hass.config_entries.async_setup(config_entry_1.entry_id)
await hass.async_block_till_done()
assert config_entry_1.state is ConfigEntryState.LOADED
# Add a second one
config_entry_2 = MockConfigEntry(
title="Example 2",
domain=DOMAIN,
)
config_entry_2.add_to_hass(hass)
await hass.config_entries.async_setup(config_entry_2.entry_id)
await hass.async_block_till_done()
assert config_entry_2.state is ConfigEntryState.LOADED
assert issue_registry.async_get_issue(DOMAIN, DOMAIN)
# Remove the first one
await hass.config_entries.async_remove(config_entry_1.entry_id)
await hass.async_block_till_done()
assert config_entry_1.state is ConfigEntryState.NOT_LOADED
assert config_entry_2.state is ConfigEntryState.LOADED
assert issue_registry.async_get_issue(DOMAIN, DOMAIN)
# Remove the second one
await hass.config_entries.async_remove(config_entry_2.entry_id)
await hass.async_block_till_done()
assert config_entry_1.state is ConfigEntryState.NOT_LOADED
assert config_entry_2.state is ConfigEntryState.NOT_LOADED
assert issue_registry.async_get_issue(DOMAIN, DOMAIN) is None