mirror of
https://github.com/home-assistant/core.git
synced 2025-07-08 13:57:10 +00:00
Deprecate HEOS sign_in and sign_out actions (#134616)
This commit is contained in:
parent
11d80065ef
commit
f68c16586d
@ -27,10 +27,12 @@ from homeassistant.const import (
|
|||||||
from homeassistant.core import CALLBACK_TYPE, HomeAssistant, callback
|
from homeassistant.core import CALLBACK_TYPE, HomeAssistant, callback
|
||||||
from homeassistant.exceptions import ConfigEntryNotReady, HomeAssistantError
|
from homeassistant.exceptions import ConfigEntryNotReady, HomeAssistantError
|
||||||
from homeassistant.helpers import device_registry as dr, entity_registry as er
|
from homeassistant.helpers import device_registry as dr, entity_registry as er
|
||||||
|
import homeassistant.helpers.config_validation as cv
|
||||||
from homeassistant.helpers.dispatcher import (
|
from homeassistant.helpers.dispatcher import (
|
||||||
async_dispatcher_connect,
|
async_dispatcher_connect,
|
||||||
async_dispatcher_send,
|
async_dispatcher_send,
|
||||||
)
|
)
|
||||||
|
from homeassistant.helpers.typing import ConfigType
|
||||||
from homeassistant.util import Throttle
|
from homeassistant.util import Throttle
|
||||||
|
|
||||||
from . import services
|
from . import services
|
||||||
@ -46,6 +48,8 @@ PLATFORMS = [Platform.MEDIA_PLAYER]
|
|||||||
|
|
||||||
MIN_UPDATE_SOURCES = timedelta(seconds=1)
|
MIN_UPDATE_SOURCES = timedelta(seconds=1)
|
||||||
|
|
||||||
|
CONFIG_SCHEMA = cv.empty_config_schema(DOMAIN)
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
@ -62,6 +66,12 @@ class HeosRuntimeData:
|
|||||||
type HeosConfigEntry = ConfigEntry[HeosRuntimeData]
|
type HeosConfigEntry = ConfigEntry[HeosRuntimeData]
|
||||||
|
|
||||||
|
|
||||||
|
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
|
||||||
|
"""Set up the HEOS component."""
|
||||||
|
services.register(hass)
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
async def async_setup_entry(hass: HomeAssistant, entry: HeosConfigEntry) -> bool:
|
async def async_setup_entry(hass: HomeAssistant, entry: HeosConfigEntry) -> bool:
|
||||||
"""Initialize config entry which represents the HEOS controller."""
|
"""Initialize config entry which represents the HEOS controller."""
|
||||||
# For backwards compat
|
# For backwards compat
|
||||||
@ -141,7 +151,6 @@ async def async_setup_entry(hass: HomeAssistant, entry: HeosConfigEntry) -> bool
|
|||||||
controller_manager, group_manager, source_manager, players
|
controller_manager, group_manager, source_manager, players
|
||||||
)
|
)
|
||||||
|
|
||||||
services.register(hass, controller)
|
|
||||||
group_manager.connect_update()
|
group_manager.connect_update()
|
||||||
entry.async_on_unload(group_manager.disconnect_update)
|
entry.async_on_unload(group_manager.disconnect_update)
|
||||||
|
|
||||||
@ -153,9 +162,6 @@ async def async_setup_entry(hass: HomeAssistant, entry: HeosConfigEntry) -> bool
|
|||||||
async def async_unload_entry(hass: HomeAssistant, entry: HeosConfigEntry) -> bool:
|
async def async_unload_entry(hass: HomeAssistant, entry: HeosConfigEntry) -> bool:
|
||||||
"""Unload a config entry."""
|
"""Unload a config entry."""
|
||||||
await entry.runtime_data.controller_manager.disconnect()
|
await entry.runtime_data.controller_manager.disconnect()
|
||||||
|
|
||||||
services.remove(hass)
|
|
||||||
|
|
||||||
return await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
|
return await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
rules:
|
rules:
|
||||||
# Bronze
|
# Bronze
|
||||||
action-setup:
|
action-setup: done
|
||||||
status: todo
|
|
||||||
comment: Future enhancement to move custom actions for login/out into an options flow.
|
|
||||||
appropriate-polling:
|
appropriate-polling:
|
||||||
status: done
|
status: done
|
||||||
comment: Integration is a local push integration
|
comment: Integration is a local push integration
|
||||||
|
@ -1,13 +1,14 @@
|
|||||||
"""Services for the HEOS integration."""
|
"""Services for the HEOS integration."""
|
||||||
|
|
||||||
import functools
|
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from pyheos import CommandFailedError, Heos, HeosError, const
|
from pyheos import CommandFailedError, Heos, HeosError, const
|
||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
|
|
||||||
|
from homeassistant.config_entries import ConfigEntryState
|
||||||
from homeassistant.core import HomeAssistant, ServiceCall
|
from homeassistant.core import HomeAssistant, ServiceCall
|
||||||
from homeassistant.helpers import config_validation as cv
|
from homeassistant.exceptions import HomeAssistantError
|
||||||
|
from homeassistant.helpers import config_validation as cv, issue_registry as ir
|
||||||
|
|
||||||
from .const import (
|
from .const import (
|
||||||
ATTR_PASSWORD,
|
ATTR_PASSWORD,
|
||||||
@ -26,30 +27,50 @@ HEOS_SIGN_IN_SCHEMA = vol.Schema(
|
|||||||
HEOS_SIGN_OUT_SCHEMA = vol.Schema({})
|
HEOS_SIGN_OUT_SCHEMA = vol.Schema({})
|
||||||
|
|
||||||
|
|
||||||
def register(hass: HomeAssistant, controller: Heos):
|
def register(hass: HomeAssistant):
|
||||||
"""Register HEOS services."""
|
"""Register HEOS services."""
|
||||||
hass.services.async_register(
|
hass.services.async_register(
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
SERVICE_SIGN_IN,
|
SERVICE_SIGN_IN,
|
||||||
functools.partial(_sign_in_handler, controller),
|
_sign_in_handler,
|
||||||
schema=HEOS_SIGN_IN_SCHEMA,
|
schema=HEOS_SIGN_IN_SCHEMA,
|
||||||
)
|
)
|
||||||
hass.services.async_register(
|
hass.services.async_register(
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
SERVICE_SIGN_OUT,
|
SERVICE_SIGN_OUT,
|
||||||
functools.partial(_sign_out_handler, controller),
|
_sign_out_handler,
|
||||||
schema=HEOS_SIGN_OUT_SCHEMA,
|
schema=HEOS_SIGN_OUT_SCHEMA,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def remove(hass: HomeAssistant):
|
def _get_controller(hass: HomeAssistant) -> Heos:
|
||||||
"""Unregister HEOS services."""
|
"""Get the HEOS controller instance."""
|
||||||
hass.services.async_remove(DOMAIN, SERVICE_SIGN_IN)
|
|
||||||
hass.services.async_remove(DOMAIN, SERVICE_SIGN_OUT)
|
_LOGGER.warning(
|
||||||
|
"Actions 'heos.sign_in' and 'heos.sign_out' are deprecated and will be removed in the 2025.8.0 release"
|
||||||
|
)
|
||||||
|
ir.async_create_issue(
|
||||||
|
hass,
|
||||||
|
DOMAIN,
|
||||||
|
"sign_in_out_deprecated",
|
||||||
|
breaks_in_ha_version="2025.8.0",
|
||||||
|
is_fixable=False,
|
||||||
|
severity=ir.IssueSeverity.WARNING,
|
||||||
|
translation_key="sign_in_out_deprecated",
|
||||||
|
)
|
||||||
|
|
||||||
|
entry = hass.config_entries.async_entry_for_domain_unique_id(DOMAIN, DOMAIN)
|
||||||
|
if not entry or not entry.state == ConfigEntryState.LOADED:
|
||||||
|
raise HomeAssistantError(
|
||||||
|
translation_domain=DOMAIN, translation_key="integration_not_loaded"
|
||||||
|
)
|
||||||
|
return entry.runtime_data.controller_manager.controller
|
||||||
|
|
||||||
|
|
||||||
async def _sign_in_handler(controller: Heos, service: ServiceCall) -> None:
|
async def _sign_in_handler(service: ServiceCall) -> None:
|
||||||
"""Sign in to the HEOS account."""
|
"""Sign in to the HEOS account."""
|
||||||
|
|
||||||
|
controller = _get_controller(service.hass)
|
||||||
if controller.connection_state != const.STATE_CONNECTED:
|
if controller.connection_state != const.STATE_CONNECTED:
|
||||||
_LOGGER.error("Unable to sign in because HEOS is not connected")
|
_LOGGER.error("Unable to sign in because HEOS is not connected")
|
||||||
return
|
return
|
||||||
@ -63,8 +84,10 @@ async def _sign_in_handler(controller: Heos, service: ServiceCall) -> None:
|
|||||||
_LOGGER.error("Unable to sign in: %s", err)
|
_LOGGER.error("Unable to sign in: %s", err)
|
||||||
|
|
||||||
|
|
||||||
async def _sign_out_handler(controller: Heos, service: ServiceCall) -> None:
|
async def _sign_out_handler(service: ServiceCall) -> None:
|
||||||
"""Sign out of the HEOS account."""
|
"""Sign out of the HEOS account."""
|
||||||
|
|
||||||
|
controller = _get_controller(service.hass)
|
||||||
if controller.connection_state != const.STATE_CONNECTED:
|
if controller.connection_state != const.STATE_CONNECTED:
|
||||||
_LOGGER.error("Unable to sign out because HEOS is not connected")
|
_LOGGER.error("Unable to sign out because HEOS is not connected")
|
||||||
return
|
return
|
||||||
|
@ -89,5 +89,16 @@
|
|||||||
"name": "Sign out",
|
"name": "Sign out",
|
||||||
"description": "Signs out of the HEOS account."
|
"description": "Signs out of the HEOS account."
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"exceptions": {
|
||||||
|
"integration_not_loaded": {
|
||||||
|
"message": "The HEOS integration is not loaded"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"issues": {
|
||||||
|
"sign_in_out_deprecated": {
|
||||||
|
"title": "HEOS Actions Deprecated",
|
||||||
|
"description": "Actions 'heos.sign_in' and 'heos.sign_out' are deprecated and will be removed in the 2025.8.0 release. Enter your HEOS Account credentials in the configuration options and the integration will manage authentication automatically."
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,7 @@ from homeassistant.components.heos.const import (
|
|||||||
SERVICE_SIGN_OUT,
|
SERVICE_SIGN_OUT,
|
||||||
)
|
)
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
|
from homeassistant.exceptions import HomeAssistantError
|
||||||
from homeassistant.setup import async_setup_component
|
from homeassistant.setup import async_setup_component
|
||||||
|
|
||||||
from tests.common import MockConfigEntry
|
from tests.common import MockConfigEntry
|
||||||
@ -91,6 +92,20 @@ async def test_sign_in_unknown_error(
|
|||||||
assert "Unable to sign in" in caplog.text
|
assert "Unable to sign in" in caplog.text
|
||||||
|
|
||||||
|
|
||||||
|
async def test_sign_in_not_loaded_raises(hass: HomeAssistant, config_entry) -> None:
|
||||||
|
"""Test the sign-in service when entry not loaded raises exception."""
|
||||||
|
await setup_component(hass, config_entry)
|
||||||
|
await hass.config_entries.async_unload(config_entry.entry_id)
|
||||||
|
|
||||||
|
with pytest.raises(HomeAssistantError, match="The HEOS integration is not loaded"):
|
||||||
|
await hass.services.async_call(
|
||||||
|
DOMAIN,
|
||||||
|
SERVICE_SIGN_IN,
|
||||||
|
{ATTR_USERNAME: "test@test.com", ATTR_PASSWORD: "password"},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
async def test_sign_out(hass: HomeAssistant, config_entry, controller) -> None:
|
async def test_sign_out(hass: HomeAssistant, config_entry, controller) -> None:
|
||||||
"""Test the sign-out service."""
|
"""Test the sign-out service."""
|
||||||
await setup_component(hass, config_entry)
|
await setup_component(hass, config_entry)
|
||||||
@ -113,6 +128,15 @@ async def test_sign_out_not_connected(
|
|||||||
assert "Unable to sign out because HEOS is not connected" in caplog.text
|
assert "Unable to sign out because HEOS is not connected" in caplog.text
|
||||||
|
|
||||||
|
|
||||||
|
async def test_sign_out_not_loaded_raises(hass: HomeAssistant, config_entry) -> None:
|
||||||
|
"""Test the sign-out service when entry not loaded raises exception."""
|
||||||
|
await setup_component(hass, config_entry)
|
||||||
|
await hass.config_entries.async_unload(config_entry.entry_id)
|
||||||
|
|
||||||
|
with pytest.raises(HomeAssistantError, match="The HEOS integration is not loaded"):
|
||||||
|
await hass.services.async_call(DOMAIN, SERVICE_SIGN_OUT, {}, blocking=True)
|
||||||
|
|
||||||
|
|
||||||
async def test_sign_out_unknown_error(
|
async def test_sign_out_unknown_error(
|
||||||
hass: HomeAssistant, config_entry, controller, caplog: pytest.LogCaptureFixture
|
hass: HomeAssistant, config_entry, controller, caplog: pytest.LogCaptureFixture
|
||||||
) -> None:
|
) -> None:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user