forked from home-assistant/core
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add HEOS sign-in/out services (home-assistant#23729)
* Add HEOS sign-in/out services * Fix typo in comment
- Loading branch information
1 parent
102beaa
commit 02d8731
Showing
9 changed files
with
220 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,13 @@ | ||
"""Const for the HEOS integration.""" | ||
|
||
ATTR_PASSWORD = "password" | ||
ATTR_USERNAME = "username" | ||
COMMAND_RETRY_ATTEMPTS = 2 | ||
COMMAND_RETRY_DELAY = 1 | ||
DATA_CONTROLLER_MANAGER = "controller" | ||
DATA_SOURCE_MANAGER = "source_manager" | ||
DATA_DISCOVERED_HOSTS = "heos_discovered_hosts" | ||
DOMAIN = 'heos' | ||
SERVICE_SIGN_IN = "sign_in" | ||
SERVICE_SIGN_OUT = "sign_out" | ||
SIGNAL_HEOS_UPDATED = "heos_updated" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
"""Services for the HEOS integration.""" | ||
import asyncio | ||
import functools | ||
import logging | ||
|
||
from pyheos import CommandError, Heos, const | ||
import voluptuous as vol | ||
|
||
from homeassistant.helpers import config_validation as cv | ||
from homeassistant.helpers.typing import HomeAssistantType | ||
|
||
from .const import ( | ||
ATTR_PASSWORD, ATTR_USERNAME, DOMAIN, SERVICE_SIGN_IN, SERVICE_SIGN_OUT) | ||
|
||
_LOGGER = logging.getLogger(__name__) | ||
|
||
HEOS_SIGN_IN_SCHEMA = vol.Schema({ | ||
vol.Required(ATTR_USERNAME): cv.string, | ||
vol.Required(ATTR_PASSWORD): cv.string | ||
}) | ||
|
||
HEOS_SIGN_OUT_SCHEMA = vol.Schema({}) | ||
|
||
|
||
def register(hass: HomeAssistantType, controller: Heos): | ||
"""Register HEOS services.""" | ||
hass.services.async_register( | ||
DOMAIN, SERVICE_SIGN_IN, | ||
functools.partial(_sign_in_handler, controller), | ||
schema=HEOS_SIGN_IN_SCHEMA) | ||
hass.services.async_register( | ||
DOMAIN, SERVICE_SIGN_OUT, | ||
functools.partial(_sign_out_handler, controller), | ||
schema=HEOS_SIGN_OUT_SCHEMA) | ||
|
||
|
||
def remove(hass: HomeAssistantType): | ||
"""Unregister HEOS services.""" | ||
hass.services.async_remove(DOMAIN, SERVICE_SIGN_IN) | ||
hass.services.async_remove(DOMAIN, SERVICE_SIGN_OUT) | ||
|
||
|
||
async def _sign_in_handler(controller, service): | ||
"""Sign in to the HEOS account.""" | ||
if controller.connection_state != const.STATE_CONNECTED: | ||
_LOGGER.error("Unable to sign in because HEOS is not connected") | ||
return | ||
username = service.data[ATTR_USERNAME] | ||
password = service.data[ATTR_PASSWORD] | ||
try: | ||
await controller.sign_in(username, password) | ||
except CommandError as err: | ||
_LOGGER.error("Sign in failed: %s", err) | ||
except (asyncio.TimeoutError, ConnectionError) as err: | ||
_LOGGER.error("Unable to sign in: %s", err) | ||
|
||
|
||
async def _sign_out_handler(controller, service): | ||
"""Sign out of the HEOS account.""" | ||
if controller.connection_state != const.STATE_CONNECTED: | ||
_LOGGER.error("Unable to sign out because HEOS is not connected") | ||
return | ||
try: | ||
await controller.sign_out() | ||
except (asyncio.TimeoutError, ConnectionError, CommandError) as err: | ||
_LOGGER.error("Unable to sign out: %s", err) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
sign_in: | ||
description: Sign the controller in to a HEOS account. | ||
fields: | ||
username: | ||
description: The username or email of the HEOS account. [Required] | ||
example: '[email protected]' | ||
password: | ||
description: The password of the HEOS account. [Required] | ||
example: 'password' | ||
|
||
sign_out: | ||
description: Sign the controller out of the HEOS account. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -35,6 +35,7 @@ def controller_fixture( | |
mock_heos.load_players.return_value = change_data | ||
mock_heos.is_signed_in = True | ||
mock_heos.signed_in_username = "[email protected]" | ||
mock_heos.connection_state = const.STATE_CONNECTED | ||
yield mock_heos | ||
|
||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
"""Tests for the services module.""" | ||
from pyheos import CommandError, const | ||
|
||
from homeassistant.components.heos.const import ( | ||
ATTR_PASSWORD, ATTR_USERNAME, DOMAIN, SERVICE_SIGN_IN, SERVICE_SIGN_OUT) | ||
from homeassistant.setup import async_setup_component | ||
|
||
|
||
async def setup_component(hass, config_entry): | ||
"""Set up the component for testing.""" | ||
config_entry.add_to_hass(hass) | ||
assert await async_setup_component(hass, DOMAIN, {}) | ||
await hass.async_block_till_done() | ||
|
||
|
||
async def test_sign_in(hass, config_entry, controller): | ||
"""Test the sign-in service.""" | ||
await setup_component(hass, config_entry) | ||
|
||
await hass.services.async_call( | ||
DOMAIN, SERVICE_SIGN_IN, | ||
{ATTR_USERNAME: "[email protected]", ATTR_PASSWORD: "password"}, | ||
blocking=True) | ||
|
||
controller.sign_in.assert_called_once_with("[email protected]", "password") | ||
|
||
|
||
async def test_sign_in_not_connected(hass, config_entry, controller, caplog): | ||
"""Test sign-in service logs error when not connected.""" | ||
await setup_component(hass, config_entry) | ||
controller.connection_state = const.STATE_RECONNECTING | ||
|
||
await hass.services.async_call( | ||
DOMAIN, SERVICE_SIGN_IN, | ||
{ATTR_USERNAME: "[email protected]", ATTR_PASSWORD: "password"}, | ||
blocking=True) | ||
|
||
assert controller.sign_in.call_count == 0 | ||
assert "Unable to sign in because HEOS is not connected" in caplog.text | ||
|
||
|
||
async def test_sign_in_failed(hass, config_entry, controller, caplog): | ||
"""Test sign-in service logs error when not connected.""" | ||
await setup_component(hass, config_entry) | ||
controller.sign_in.side_effect = CommandError("", "Invalid credentials", 6) | ||
|
||
await hass.services.async_call( | ||
DOMAIN, SERVICE_SIGN_IN, | ||
{ATTR_USERNAME: "[email protected]", ATTR_PASSWORD: "password"}, | ||
blocking=True) | ||
|
||
controller.sign_in.assert_called_once_with("[email protected]", "password") | ||
assert "Sign in failed: Invalid credentials (6)" in caplog.text | ||
|
||
|
||
async def test_sign_in_unknown_error(hass, config_entry, controller, caplog): | ||
"""Test sign-in service logs error for failure.""" | ||
await setup_component(hass, config_entry) | ||
controller.sign_in.side_effect = ConnectionError | ||
|
||
await hass.services.async_call( | ||
DOMAIN, SERVICE_SIGN_IN, | ||
{ATTR_USERNAME: "[email protected]", ATTR_PASSWORD: "password"}, | ||
blocking=True) | ||
|
||
controller.sign_in.assert_called_once_with("[email protected]", "password") | ||
assert "Unable to sign in" in caplog.text | ||
|
||
|
||
async def test_sign_out(hass, config_entry, controller): | ||
"""Test the sign-out service.""" | ||
await setup_component(hass, config_entry) | ||
|
||
await hass.services.async_call(DOMAIN, SERVICE_SIGN_OUT, {}, blocking=True) | ||
|
||
assert controller.sign_out.call_count == 1 | ||
|
||
|
||
async def test_sign_out_not_connected(hass, config_entry, controller, caplog): | ||
"""Test the sign-out service.""" | ||
await setup_component(hass, config_entry) | ||
controller.connection_state = const.STATE_RECONNECTING | ||
|
||
await hass.services.async_call(DOMAIN, SERVICE_SIGN_OUT, {}, blocking=True) | ||
|
||
assert controller.sign_out.call_count == 0 | ||
assert "Unable to sign out because HEOS is not connected" in caplog.text | ||
|
||
|
||
async def test_sign_out_unknown_error(hass, config_entry, controller, caplog): | ||
"""Test the sign-out service.""" | ||
await setup_component(hass, config_entry) | ||
controller.sign_out.side_effect = ConnectionError | ||
|
||
await hass.services.async_call(DOMAIN, SERVICE_SIGN_OUT, {}, blocking=True) | ||
|
||
assert controller.sign_out.call_count == 1 | ||
assert "Unable to sign out" in caplog.text |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters