Remove JuiceNet integration (#147206)

This commit is contained in:
epenet
2025-06-23 21:46:51 +02:00
committed by GitHub
parent 7f99cd2d2b
commit 8b6205be25
18 changed files with 80 additions and 702 deletions

2
CODEOWNERS generated
View File

@ -788,8 +788,6 @@ build.json @home-assistant/supervisor
/tests/components/jellyfin/ @RunC0deRun @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,95 +1,36 @@
"""The JuiceNet integration."""
import logging
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 import issue_registry as ir
from .const import DOMAIN, JUICENET_API, JUICENET_COORDINATOR
from .coordinator import JuiceNetCoordinator
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
from .const import DOMAIN
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.debug("%d JuiceNet device(s) found", len(juicenet.devices))
coordinator = JuiceNetCoordinator(hass, entry, 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)
ir.async_create_issue(
hass,
DOMAIN,
DOMAIN,
is_fixable=False,
severity=ir.IssueSeverity.ERROR,
translation_key="integration_removed",
translation_placeholders={
"entries": "/config/integrations/integration/juicenet",
},
)
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,82 +1,11 @@
"""Config flow for JuiceNet integration."""
import logging
from typing import Any
import aiohttp
from pyjuicenet import Api, TokenError
import voluptuous as vol
from homeassistant import core, exceptions
from homeassistant.config_entries import ConfigFlow, ConfigFlowResult
from homeassistant.const import CONF_ACCESS_TOKEN
from homeassistant.helpers.aiohttp_client import async_get_clientsession
from homeassistant.config_entries import ConfigFlow
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"}
class JuiceNetConfigFlow(ConfigFlow, domain=DOMAIN):
"""Handle a config flow for JuiceNet."""
VERSION = 1
async def async_step_user(
self, user_input: dict[str, Any] | None = None
) -> ConfigFlowResult:
"""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:
_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, import_data: dict[str, Any]) -> ConfigFlowResult:
"""Handle import."""
return await self.async_step_user(import_data)
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 +1,3 @@
"""Constants used by the JuiceNet component."""
DOMAIN = "juicenet"
JUICENET_API = "juicenet_api"
JUICENET_COORDINATOR = "juicenet_coordinator"

View File

@ -1,33 +0,0 @@
"""The JuiceNet integration."""
from datetime import timedelta
import logging
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
from .device import JuiceNetApi
_LOGGER = logging.getLogger(__name__)
class JuiceNetCoordinator(DataUpdateCoordinator[None]):
"""Coordinator for JuiceNet."""
def __init__(
self, hass: HomeAssistant, entry: ConfigEntry, juicenet_api: JuiceNetApi
) -> None:
"""Initialize the JuiceNet coordinator."""
super().__init__(
hass,
_LOGGER,
config_entry=entry,
name="JuiceNet",
update_interval=timedelta(seconds=30),
)
self.juicenet_api = juicenet_api
async def _async_update_data(self) -> None:
for device in self.juicenet_api.devices:
await device.update_state(True)

View File

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

View File

@ -1,32 +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
from .const import DOMAIN
from .coordinator import JuiceNetCoordinator
class JuiceNetEntity(CoordinatorEntity[JuiceNetCoordinator]):
"""Represent a base JuiceNet device."""
_attr_has_entity_name = True
def __init__(
self, device: Charger, key: str, coordinator: JuiceNetCoordinator
) -> 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,93 +0,0 @@
"""Support for controlling juicenet/juicepoint/juicebox based EVSE numbers."""
from __future__ import annotations
from dataclasses import dataclass
from pyjuicenet import 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 AddConfigEntryEntitiesCallback
from .const import DOMAIN, JUICENET_API, JUICENET_COORDINATOR
from .coordinator import JuiceNetCoordinator
from .device import JuiceNetApi
from .entity import JuiceNetEntity
@dataclass(frozen=True, kw_only=True)
class JuiceNetNumberEntityDescription(NumberEntityDescription):
"""An entity description for a JuiceNetNumber."""
setter_key: str
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: AddConfigEntryEntitiesCallback,
) -> None:
"""Set up the JuiceNet Numbers."""
juicenet_data = hass.data[DOMAIN][config_entry.entry_id]
api: JuiceNetApi = juicenet_data[JUICENET_API]
coordinator: JuiceNetCoordinator = 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(JuiceNetEntity, NumberEntity):
"""Implementation of a JuiceNet number."""
entity_description: JuiceNetNumberEntityDescription
def __init__(
self,
device: Charger,
description: JuiceNetNumberEntityDescription,
coordinator: JuiceNetCoordinator,
) -> 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,124 +0,0 @@
"""Support for monitoring juicenet/juicepoint/juicebox based EVSE sensors."""
from __future__ import annotations
from pyjuicenet import Charger
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 AddConfigEntryEntitiesCallback
from .const import DOMAIN, JUICENET_API, JUICENET_COORDINATOR
from .coordinator import JuiceNetCoordinator
from .device import JuiceNetApi
from .entity import JuiceNetEntity
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: AddConfigEntryEntitiesCallback,
) -> None:
"""Set up the JuiceNet Sensors."""
juicenet_data = hass.data[DOMAIN][config_entry.entry_id]
api: JuiceNetApi = juicenet_data[JUICENET_API]
coordinator: JuiceNetCoordinator = 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(JuiceNetEntity, SensorEntity):
"""Implementation of a JuiceNet sensor."""
def __init__(
self,
device: Charger,
coordinator: JuiceNetCoordinator,
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,53 +0,0 @@
"""Support for monitoring juicenet/juicepoint/juicebox based EVSE switches."""
from typing import Any
from pyjuicenet import Charger
from homeassistant.components.switch import SwitchEntity
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
from .const import DOMAIN, JUICENET_API, JUICENET_COORDINATOR
from .coordinator import JuiceNetCoordinator
from .device import JuiceNetApi
from .entity import JuiceNetEntity
async def async_setup_entry(
hass: HomeAssistant,
config_entry: ConfigEntry,
async_add_entities: AddConfigEntryEntitiesCallback,
) -> None:
"""Set up the JuiceNet switches."""
juicenet_data = hass.data[DOMAIN][config_entry.entry_id]
api: JuiceNetApi = juicenet_data[JUICENET_API]
coordinator: JuiceNetCoordinator = juicenet_data[JUICENET_COORDINATOR]
async_add_entities(
JuiceNetChargeNowSwitch(device, coordinator) for device in api.devices
)
class JuiceNetChargeNowSwitch(JuiceNetEntity, SwitchEntity):
"""Implementation of a JuiceNet switch."""
_attr_translation_key = "charge_now"
def __init__(self, device: Charger, coordinator: JuiceNetCoordinator) -> None:
"""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

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

View File

@ -3181,12 +3181,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",

3
requirements_all.txt generated
View File

@ -2449,9 +2449,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.10.2

View File

@ -2019,9 +2019,6 @@ python-homewizard-energy==9.1.1
# homeassistant.components.izone
python-izone==1.2.9
# homeassistant.components.juicenet
python-juicenet==1.1.0
# homeassistant.components.tplink
python-kasa[speedups]==0.10.2

View File

@ -1,134 +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
from homeassistant.data_entry_flow import FlowResultType
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"] is FlowResultType.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"] is FlowResultType.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"] is FlowResultType.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"] is FlowResultType.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"] is FlowResultType.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"] is FlowResultType.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