mirror of
https://github.com/home-assistant/core.git
synced 2025-07-27 23:27:37 +00:00
Arcam config flow (#34384)
Co-authored-by: J. Nick Koston <nick@koston.org> Co-authored-by: Paulus Schoutsen <paulus@home-assistant.io>
This commit is contained in:
parent
524b48be7d
commit
31973de2d5
@ -5,27 +5,15 @@ import logging
|
|||||||
from arcam.fmj import ConnectionFailed
|
from arcam.fmj import ConnectionFailed
|
||||||
from arcam.fmj.client import Client
|
from arcam.fmj.client import Client
|
||||||
import async_timeout
|
import async_timeout
|
||||||
import voluptuous as vol
|
|
||||||
|
|
||||||
from homeassistant import config_entries
|
from homeassistant import config_entries
|
||||||
from homeassistant.const import (
|
from homeassistant.const import CONF_HOST, CONF_PORT, EVENT_HOMEASSISTANT_STOP
|
||||||
CONF_HOST,
|
|
||||||
CONF_NAME,
|
|
||||||
CONF_PORT,
|
|
||||||
CONF_SCAN_INTERVAL,
|
|
||||||
CONF_ZONE,
|
|
||||||
EVENT_HOMEASSISTANT_STOP,
|
|
||||||
SERVICE_TURN_ON,
|
|
||||||
)
|
|
||||||
import homeassistant.helpers.config_validation as cv
|
import homeassistant.helpers.config_validation as cv
|
||||||
from homeassistant.helpers.typing import ConfigType, HomeAssistantType
|
from homeassistant.helpers.typing import ConfigType, HomeAssistantType
|
||||||
|
|
||||||
from .const import (
|
from .const import (
|
||||||
DEFAULT_NAME,
|
|
||||||
DEFAULT_PORT,
|
|
||||||
DEFAULT_SCAN_INTERVAL,
|
DEFAULT_SCAN_INTERVAL,
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
DOMAIN_DATA_CONFIG,
|
|
||||||
DOMAIN_DATA_ENTRIES,
|
DOMAIN_DATA_ENTRIES,
|
||||||
DOMAIN_DATA_TASKS,
|
DOMAIN_DATA_TASKS,
|
||||||
SIGNAL_CLIENT_DATA,
|
SIGNAL_CLIENT_DATA,
|
||||||
@ -35,44 +23,7 @@ from .const import (
|
|||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
CONFIG_SCHEMA = cv.deprecated(DOMAIN, invalidation_version="0.115")
|
||||||
def _optional_zone(value):
|
|
||||||
if value:
|
|
||||||
return ZONE_SCHEMA(value)
|
|
||||||
return ZONE_SCHEMA({})
|
|
||||||
|
|
||||||
|
|
||||||
def _zone_name_validator(config):
|
|
||||||
for zone, zone_config in config[CONF_ZONE].items():
|
|
||||||
if CONF_NAME not in zone_config:
|
|
||||||
zone_config[
|
|
||||||
CONF_NAME
|
|
||||||
] = f"{DEFAULT_NAME} ({config[CONF_HOST]}:{config[CONF_PORT]}) - {zone}"
|
|
||||||
return config
|
|
||||||
|
|
||||||
|
|
||||||
ZONE_SCHEMA = vol.Schema(
|
|
||||||
{
|
|
||||||
vol.Optional(CONF_NAME): cv.string,
|
|
||||||
vol.Optional(SERVICE_TURN_ON): cv.SERVICE_SCHEMA,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
DEVICE_SCHEMA = vol.Schema(
|
|
||||||
vol.All(
|
|
||||||
{
|
|
||||||
vol.Required(CONF_HOST): cv.string,
|
|
||||||
vol.Required(CONF_PORT, default=DEFAULT_PORT): cv.positive_int,
|
|
||||||
vol.Optional(CONF_ZONE, default={1: _optional_zone(None)}): {
|
|
||||||
vol.In([1, 2]): _optional_zone
|
|
||||||
},
|
|
||||||
vol.Optional(
|
|
||||||
CONF_SCAN_INTERVAL, default=DEFAULT_SCAN_INTERVAL
|
|
||||||
): cv.positive_int,
|
|
||||||
},
|
|
||||||
_zone_name_validator,
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
async def _await_cancel(task):
|
async def _await_cancel(task):
|
||||||
@ -83,27 +34,10 @@ async def _await_cancel(task):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
CONFIG_SCHEMA = vol.Schema(
|
|
||||||
{DOMAIN: vol.All(cv.ensure_list, [DEVICE_SCHEMA])}, extra=vol.ALLOW_EXTRA
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
async def async_setup(hass: HomeAssistantType, config: ConfigType):
|
async def async_setup(hass: HomeAssistantType, config: ConfigType):
|
||||||
"""Set up the component."""
|
"""Set up the component."""
|
||||||
hass.data[DOMAIN_DATA_ENTRIES] = {}
|
hass.data[DOMAIN_DATA_ENTRIES] = {}
|
||||||
hass.data[DOMAIN_DATA_TASKS] = {}
|
hass.data[DOMAIN_DATA_TASKS] = {}
|
||||||
hass.data[DOMAIN_DATA_CONFIG] = {}
|
|
||||||
|
|
||||||
for device in config[DOMAIN]:
|
|
||||||
hass.data[DOMAIN_DATA_CONFIG][(device[CONF_HOST], device[CONF_PORT])] = device
|
|
||||||
|
|
||||||
hass.async_create_task(
|
|
||||||
hass.config_entries.flow.async_init(
|
|
||||||
DOMAIN,
|
|
||||||
context={"source": config_entries.SOURCE_IMPORT},
|
|
||||||
data={CONF_HOST: device[CONF_HOST], CONF_PORT: device[CONF_PORT]},
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
async def _stop(_):
|
async def _stop(_):
|
||||||
asyncio.gather(
|
asyncio.gather(
|
||||||
@ -116,21 +50,12 @@ async def async_setup(hass: HomeAssistantType, config: ConfigType):
|
|||||||
|
|
||||||
|
|
||||||
async def async_setup_entry(hass: HomeAssistantType, entry: config_entries.ConfigEntry):
|
async def async_setup_entry(hass: HomeAssistantType, entry: config_entries.ConfigEntry):
|
||||||
"""Set up an access point from a config entry."""
|
"""Set up config entry."""
|
||||||
|
entries = hass.data[DOMAIN_DATA_ENTRIES]
|
||||||
|
tasks = hass.data[DOMAIN_DATA_TASKS]
|
||||||
|
|
||||||
client = Client(entry.data[CONF_HOST], entry.data[CONF_PORT])
|
client = Client(entry.data[CONF_HOST], entry.data[CONF_PORT])
|
||||||
|
entries[entry.entry_id] = client
|
||||||
config = hass.data[DOMAIN_DATA_CONFIG].get(
|
|
||||||
(entry.data[CONF_HOST], entry.data[CONF_PORT]),
|
|
||||||
DEVICE_SCHEMA(
|
|
||||||
{CONF_HOST: entry.data[CONF_HOST], CONF_PORT: entry.data[CONF_PORT]}
|
|
||||||
),
|
|
||||||
)
|
|
||||||
tasks = hass.data.setdefault(DOMAIN_DATA_TASKS, {})
|
|
||||||
|
|
||||||
hass.data[DOMAIN_DATA_ENTRIES][entry.entry_id] = {
|
|
||||||
"client": client,
|
|
||||||
"config": config,
|
|
||||||
}
|
|
||||||
|
|
||||||
task = asyncio.create_task(_run_client(hass, client, DEFAULT_SCAN_INTERVAL))
|
task = asyncio.create_task(_run_client(hass, client, DEFAULT_SCAN_INTERVAL))
|
||||||
tasks[entry.entry_id] = task
|
tasks[entry.entry_id] = task
|
||||||
|
@ -1,27 +1,102 @@
|
|||||||
"""Config flow to configure the Arcam FMJ component."""
|
"""Config flow to configure the Arcam FMJ component."""
|
||||||
from operator import itemgetter
|
import logging
|
||||||
|
from urllib.parse import urlparse
|
||||||
|
|
||||||
|
from arcam.fmj.client import Client, ConnectionFailed
|
||||||
|
from arcam.fmj.utils import get_uniqueid_from_host, get_uniqueid_from_udn
|
||||||
|
import voluptuous as vol
|
||||||
|
|
||||||
from homeassistant import config_entries
|
from homeassistant import config_entries
|
||||||
|
from homeassistant.components.ssdp import ATTR_SSDP_LOCATION, ATTR_UPNP_UDN
|
||||||
from homeassistant.const import CONF_HOST, CONF_PORT
|
from homeassistant.const import CONF_HOST, CONF_PORT
|
||||||
|
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
||||||
|
|
||||||
from .const import DOMAIN
|
from .const import DEFAULT_NAME, DEFAULT_PORT, DOMAIN, DOMAIN_DATA_ENTRIES
|
||||||
|
|
||||||
_GETKEY = itemgetter(CONF_HOST, CONF_PORT)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
def get_entry_client(hass, entry):
|
||||||
|
"""Retrieve client associated with a config entry."""
|
||||||
|
return hass.data[DOMAIN_DATA_ENTRIES][entry.entry_id]
|
||||||
|
|
||||||
|
|
||||||
@config_entries.HANDLERS.register(DOMAIN)
|
@config_entries.HANDLERS.register(DOMAIN)
|
||||||
class ArcamFmjFlowHandler(config_entries.ConfigFlow):
|
class ArcamFmjFlowHandler(config_entries.ConfigFlow):
|
||||||
"""Handle a SimpliSafe config flow."""
|
"""Handle config flow."""
|
||||||
|
|
||||||
VERSION = 1
|
VERSION = 1
|
||||||
CONNECTION_CLASS = config_entries.CONN_CLASS_LOCAL_POLL
|
CONNECTION_CLASS = config_entries.CONN_CLASS_LOCAL_POLL
|
||||||
|
|
||||||
async def async_step_import(self, import_config):
|
async def _async_set_unique_id_and_update(self, host, port, uuid):
|
||||||
"""Import a config entry from configuration.yaml."""
|
await self.async_set_unique_id(uuid)
|
||||||
entries = self.hass.config_entries.async_entries(DOMAIN)
|
self._abort_if_unique_id_configured({CONF_HOST: host, CONF_PORT: port})
|
||||||
import_key = _GETKEY(import_config)
|
|
||||||
for entry in entries:
|
|
||||||
if _GETKEY(entry.data) == import_key:
|
|
||||||
return self.async_abort(reason="already_setup")
|
|
||||||
|
|
||||||
return self.async_create_entry(title="Arcam FMJ", data=import_config)
|
async def _async_check_and_create(self, host, port):
|
||||||
|
client = Client(host, port)
|
||||||
|
try:
|
||||||
|
await client.start()
|
||||||
|
except ConnectionFailed:
|
||||||
|
return self.async_abort(reason="unable_to_connect")
|
||||||
|
finally:
|
||||||
|
await client.stop()
|
||||||
|
|
||||||
|
return self.async_create_entry(
|
||||||
|
title=f"{DEFAULT_NAME} ({host})", data={CONF_HOST: host, CONF_PORT: port},
|
||||||
|
)
|
||||||
|
|
||||||
|
async def async_step_user(self, user_info=None):
|
||||||
|
"""Handle a discovered device."""
|
||||||
|
errors = {}
|
||||||
|
|
||||||
|
if user_info is not None:
|
||||||
|
uuid = await get_uniqueid_from_host(
|
||||||
|
async_get_clientsession(self.hass), user_info[CONF_HOST]
|
||||||
|
)
|
||||||
|
if uuid:
|
||||||
|
await self._async_set_unique_id_and_update(
|
||||||
|
user_info[CONF_HOST], user_info[CONF_PORT], uuid
|
||||||
|
)
|
||||||
|
|
||||||
|
return await self._async_check_and_create(
|
||||||
|
user_info[CONF_HOST], user_info[CONF_PORT]
|
||||||
|
)
|
||||||
|
|
||||||
|
fields = {
|
||||||
|
vol.Required(CONF_HOST): str,
|
||||||
|
vol.Required(CONF_PORT, default=DEFAULT_PORT): int,
|
||||||
|
}
|
||||||
|
|
||||||
|
return self.async_show_form(
|
||||||
|
step_id="user", data_schema=vol.Schema(fields), errors=errors
|
||||||
|
)
|
||||||
|
|
||||||
|
async def async_step_confirm(self, user_input=None):
|
||||||
|
"""Handle user-confirmation of discovered node."""
|
||||||
|
context = self.context # pylint: disable=no-member
|
||||||
|
placeholders = {
|
||||||
|
"host": context[CONF_HOST],
|
||||||
|
}
|
||||||
|
context["title_placeholders"] = placeholders
|
||||||
|
|
||||||
|
if user_input is not None:
|
||||||
|
return await self._async_check_and_create(
|
||||||
|
context[CONF_HOST], context[CONF_PORT]
|
||||||
|
)
|
||||||
|
|
||||||
|
return self.async_show_form(
|
||||||
|
step_id="confirm", description_placeholders=placeholders
|
||||||
|
)
|
||||||
|
|
||||||
|
async def async_step_ssdp(self, discovery_info):
|
||||||
|
"""Handle a discovered device."""
|
||||||
|
host = urlparse(discovery_info[ATTR_SSDP_LOCATION]).hostname
|
||||||
|
port = DEFAULT_PORT
|
||||||
|
uuid = get_uniqueid_from_udn(discovery_info[ATTR_UPNP_UDN])
|
||||||
|
|
||||||
|
await self._async_set_unique_id_and_update(host, port, uuid)
|
||||||
|
|
||||||
|
context = self.context # pylint: disable=no-member
|
||||||
|
context[CONF_HOST] = host
|
||||||
|
context[CONF_PORT] = DEFAULT_PORT
|
||||||
|
return await self.async_step_confirm()
|
||||||
|
@ -13,4 +13,3 @@ DEFAULT_SCAN_INTERVAL = 5
|
|||||||
|
|
||||||
DOMAIN_DATA_ENTRIES = f"{DOMAIN}.entries"
|
DOMAIN_DATA_ENTRIES = f"{DOMAIN}.entries"
|
||||||
DOMAIN_DATA_TASKS = f"{DOMAIN}.tasks"
|
DOMAIN_DATA_TASKS = f"{DOMAIN}.tasks"
|
||||||
DOMAIN_DATA_CONFIG = f"{DOMAIN}.config"
|
|
||||||
|
@ -1,8 +1,14 @@
|
|||||||
{
|
{
|
||||||
"domain": "arcam_fmj",
|
"domain": "arcam_fmj",
|
||||||
"name": "Arcam FMJ Receivers",
|
"name": "Arcam FMJ Receivers",
|
||||||
"config_flow": false,
|
"config_flow": true,
|
||||||
"documentation": "https://www.home-assistant.io/integrations/arcam_fmj",
|
"documentation": "https://www.home-assistant.io/integrations/arcam_fmj",
|
||||||
"requirements": ["arcam-fmj==0.4.6"],
|
"requirements": ["arcam-fmj==0.5.1"],
|
||||||
|
"ssdp": [
|
||||||
|
{
|
||||||
|
"deviceType": "urn:schemas-upnp-org:device:MediaRenderer:1",
|
||||||
|
"manufacturer": "ARCAM"
|
||||||
|
}
|
||||||
|
],
|
||||||
"codeowners": ["@elupus"]
|
"codeowners": ["@elupus"]
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
"""Arcam media player."""
|
"""Arcam media player."""
|
||||||
import logging
|
import logging
|
||||||
from typing import Optional
|
|
||||||
|
|
||||||
from arcam.fmj import DecodeMode2CH, DecodeModeMCH, IncomingAudioFormat, SourceCodes
|
from arcam.fmj import DecodeMode2CH, DecodeModeMCH, IncomingAudioFormat, SourceCodes
|
||||||
from arcam.fmj.state import State
|
from arcam.fmj.state import State
|
||||||
@ -17,21 +16,13 @@ from homeassistant.components.media_player.const import (
|
|||||||
SUPPORT_VOLUME_SET,
|
SUPPORT_VOLUME_SET,
|
||||||
SUPPORT_VOLUME_STEP,
|
SUPPORT_VOLUME_STEP,
|
||||||
)
|
)
|
||||||
from homeassistant.const import (
|
from homeassistant.const import ATTR_ENTITY_ID, STATE_OFF, STATE_ON
|
||||||
ATTR_ENTITY_ID,
|
|
||||||
CONF_NAME,
|
|
||||||
CONF_ZONE,
|
|
||||||
SERVICE_TURN_ON,
|
|
||||||
STATE_OFF,
|
|
||||||
STATE_ON,
|
|
||||||
)
|
|
||||||
from homeassistant.core import callback
|
from homeassistant.core import callback
|
||||||
from homeassistant.helpers.service import async_call_from_config
|
from homeassistant.helpers.typing import HomeAssistantType
|
||||||
from homeassistant.helpers.typing import ConfigType, HomeAssistantType
|
|
||||||
|
|
||||||
|
from .config_flow import get_entry_client
|
||||||
from .const import (
|
from .const import (
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
DOMAIN_DATA_ENTRIES,
|
|
||||||
EVENT_TURN_ON,
|
EVENT_TURN_ON,
|
||||||
SIGNAL_CLIENT_DATA,
|
SIGNAL_CLIENT_DATA,
|
||||||
SIGNAL_CLIENT_STARTED,
|
SIGNAL_CLIENT_STARTED,
|
||||||
@ -47,19 +38,17 @@ async def async_setup_entry(
|
|||||||
async_add_entities,
|
async_add_entities,
|
||||||
):
|
):
|
||||||
"""Set up the configuration entry."""
|
"""Set up the configuration entry."""
|
||||||
data = hass.data[DOMAIN_DATA_ENTRIES][config_entry.entry_id]
|
|
||||||
client = data["client"]
|
client = get_entry_client(hass, config_entry)
|
||||||
config = data["config"]
|
|
||||||
|
|
||||||
async_add_entities(
|
async_add_entities(
|
||||||
[
|
[
|
||||||
ArcamFmj(
|
ArcamFmj(
|
||||||
|
config_entry.title,
|
||||||
State(client, zone),
|
State(client, zone),
|
||||||
config_entry.unique_id or config_entry.entry_id,
|
config_entry.unique_id or config_entry.entry_id,
|
||||||
zone_config[CONF_NAME],
|
|
||||||
zone_config.get(SERVICE_TURN_ON),
|
|
||||||
)
|
)
|
||||||
for zone, zone_config in config[CONF_ZONE].items()
|
for zone in [1, 2]
|
||||||
],
|
],
|
||||||
True,
|
True,
|
||||||
)
|
)
|
||||||
@ -71,13 +60,13 @@ class ArcamFmj(MediaPlayerEntity):
|
|||||||
"""Representation of a media device."""
|
"""Representation of a media device."""
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self, state: State, uuid: str, name: str, turn_on: Optional[ConfigType]
|
self, device_name, state: State, uuid: str,
|
||||||
):
|
):
|
||||||
"""Initialize device."""
|
"""Initialize device."""
|
||||||
self._state = state
|
self._state = state
|
||||||
|
self._device_name = device_name
|
||||||
|
self._name = f"{device_name} - Zone: {state.zn}"
|
||||||
self._uuid = uuid
|
self._uuid = uuid
|
||||||
self._name = name
|
|
||||||
self._turn_on = turn_on
|
|
||||||
self._support = (
|
self._support = (
|
||||||
SUPPORT_SELECT_SOURCE
|
SUPPORT_SELECT_SOURCE
|
||||||
| SUPPORT_VOLUME_SET
|
| SUPPORT_VOLUME_SET
|
||||||
@ -102,6 +91,11 @@ class ArcamFmj(MediaPlayerEntity):
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def entity_registry_enabled_default(self) -> bool:
|
||||||
|
"""Return if the entity should be enabled when first added to the entity registry."""
|
||||||
|
return self._state.zn == 1
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def unique_id(self):
|
def unique_id(self):
|
||||||
"""Return unique identifier if known."""
|
"""Return unique identifier if known."""
|
||||||
@ -111,8 +105,12 @@ class ArcamFmj(MediaPlayerEntity):
|
|||||||
def device_info(self):
|
def device_info(self):
|
||||||
"""Return a device description for device registry."""
|
"""Return a device description for device registry."""
|
||||||
return {
|
return {
|
||||||
"identifiers": {(DOMAIN, self._state.client.host, self._state.client.port)},
|
"name": self._device_name,
|
||||||
"model": "FMJ",
|
"identifiers": {
|
||||||
|
(DOMAIN, self._uuid),
|
||||||
|
(DOMAIN, self._state.client.host, self._state.client.port),
|
||||||
|
},
|
||||||
|
"model": "Arcam FMJ AVR",
|
||||||
"manufacturer": "Arcam",
|
"manufacturer": "Arcam",
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -229,15 +227,6 @@ class ArcamFmj(MediaPlayerEntity):
|
|||||||
if self._state.get_power() is not None:
|
if self._state.get_power() is not None:
|
||||||
_LOGGER.debug("Turning on device using connection")
|
_LOGGER.debug("Turning on device using connection")
|
||||||
await self._state.set_power(True)
|
await self._state.set_power(True)
|
||||||
elif self._turn_on:
|
|
||||||
_LOGGER.debug("Turning on device using service call")
|
|
||||||
await async_call_from_config(
|
|
||||||
self.hass,
|
|
||||||
self._turn_on,
|
|
||||||
variables=None,
|
|
||||||
blocking=True,
|
|
||||||
validate_config=False,
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
_LOGGER.debug("Firing event to turn on device")
|
_LOGGER.debug("Firing event to turn on device")
|
||||||
self.hass.bus.async_fire(EVENT_TURN_ON, {ATTR_ENTITY_ID: self.entity_id})
|
self.hass.bus.async_fire(EVENT_TURN_ON, {ATTR_ENTITY_ID: self.entity_id})
|
||||||
|
@ -1,7 +1,28 @@
|
|||||||
{
|
{
|
||||||
|
"config": {
|
||||||
|
"abort": {
|
||||||
|
"already_configured": "Device was already setup.",
|
||||||
|
"already_in_progress": "Config flow for device is already in progress.",
|
||||||
|
"unable_to_connect": "Unable to connect to device."
|
||||||
|
},
|
||||||
|
"error": {},
|
||||||
|
"flow_title": "Arcam FMJ on {host}",
|
||||||
|
"step": {
|
||||||
|
"confirm": {
|
||||||
|
"description": "Do you want to add Arcam FMJ on `{host}` to Home Assistant?"
|
||||||
|
},
|
||||||
|
"user": {
|
||||||
|
"data": {
|
||||||
|
"host": "[%key:common::config_flow::data::host%]",
|
||||||
|
"port": "[%key:common::config_flow::data::port%]"
|
||||||
|
},
|
||||||
|
"description": "Please enter the host name or IP address of device."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"device_automation": {
|
"device_automation": {
|
||||||
"trigger_type": {
|
"trigger_type": {
|
||||||
"turn_on": "{entity_name} was requested to turn on"
|
"turn_on": "{entity_name} was requested to turn on"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,26 @@
|
|||||||
{
|
{
|
||||||
|
"title": "Arcam FMJ",
|
||||||
|
"config": {
|
||||||
|
"abort": {
|
||||||
|
"already_configured": "Device was already setup.",
|
||||||
|
"already_in_progress": "Config flow for device is already in progress.",
|
||||||
|
"unable_to_connect": "Unable to connect to device."
|
||||||
|
},
|
||||||
|
"error": {},
|
||||||
|
"flow_title": "Arcam FMJ on {host}",
|
||||||
|
"step": {
|
||||||
|
"confirm": {
|
||||||
|
"description": "Do you want to add Arcam FMJ on `{host}` to Home Assistant?"
|
||||||
|
},
|
||||||
|
"user": {
|
||||||
|
"data": {
|
||||||
|
"host": "Host",
|
||||||
|
"port": "Port"
|
||||||
|
},
|
||||||
|
"description": "Please enter the host name or IP address of device."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"device_automation": {
|
"device_automation": {
|
||||||
"trigger_type": {
|
"trigger_type": {
|
||||||
"turn_on": "{entity_name} was requested to turn on"
|
"turn_on": "{entity_name} was requested to turn on"
|
||||||
|
@ -15,6 +15,7 @@ FLOWS = [
|
|||||||
"almond",
|
"almond",
|
||||||
"ambiclimate",
|
"ambiclimate",
|
||||||
"ambient_station",
|
"ambient_station",
|
||||||
|
"arcam_fmj",
|
||||||
"atag",
|
"atag",
|
||||||
"august",
|
"august",
|
||||||
"avri",
|
"avri",
|
||||||
|
@ -6,6 +6,12 @@ To update, run python3 -m script.hassfest
|
|||||||
# fmt: off
|
# fmt: off
|
||||||
|
|
||||||
SSDP = {
|
SSDP = {
|
||||||
|
"arcam_fmj": [
|
||||||
|
{
|
||||||
|
"deviceType": "urn:schemas-upnp-org:device:MediaRenderer:1",
|
||||||
|
"manufacturer": "ARCAM"
|
||||||
|
}
|
||||||
|
],
|
||||||
"deconz": [
|
"deconz": [
|
||||||
{
|
{
|
||||||
"manufacturer": "Royal Philips Electronics"
|
"manufacturer": "Royal Philips Electronics"
|
||||||
|
@ -272,7 +272,7 @@ aprslib==0.6.46
|
|||||||
aqualogic==1.0
|
aqualogic==1.0
|
||||||
|
|
||||||
# homeassistant.components.arcam_fmj
|
# homeassistant.components.arcam_fmj
|
||||||
arcam-fmj==0.4.6
|
arcam-fmj==0.5.1
|
||||||
|
|
||||||
# homeassistant.components.arris_tg2492lg
|
# homeassistant.components.arris_tg2492lg
|
||||||
arris-tg2492lg==1.0.0
|
arris-tg2492lg==1.0.0
|
||||||
|
@ -137,7 +137,7 @@ apprise==0.8.5
|
|||||||
aprslib==0.6.46
|
aprslib==0.6.46
|
||||||
|
|
||||||
# homeassistant.components.arcam_fmj
|
# homeassistant.components.arcam_fmj
|
||||||
arcam-fmj==0.4.6
|
arcam-fmj==0.5.1
|
||||||
|
|
||||||
# homeassistant.components.dlna_dmr
|
# homeassistant.components.dlna_dmr
|
||||||
# homeassistant.components.upnp
|
# homeassistant.components.upnp
|
||||||
|
@ -3,30 +3,24 @@ from arcam.fmj.client import Client
|
|||||||
from arcam.fmj.state import State
|
from arcam.fmj.state import State
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from homeassistant.components.arcam_fmj import DEVICE_SCHEMA
|
from homeassistant.components.arcam_fmj.const import DEFAULT_NAME
|
||||||
from homeassistant.components.arcam_fmj.const import DOMAIN
|
|
||||||
from homeassistant.components.arcam_fmj.media_player import ArcamFmj
|
from homeassistant.components.arcam_fmj.media_player import ArcamFmj
|
||||||
from homeassistant.const import CONF_HOST, CONF_PORT
|
from homeassistant.const import CONF_HOST, CONF_PORT
|
||||||
from homeassistant.setup import async_setup_component
|
|
||||||
|
|
||||||
from tests.async_mock import Mock, patch
|
from tests.async_mock import Mock, patch
|
||||||
|
from tests.common import MockConfigEntry
|
||||||
|
|
||||||
MOCK_HOST = "127.0.0.1"
|
MOCK_HOST = "127.0.0.1"
|
||||||
MOCK_PORT = 1234
|
MOCK_PORT = 50000
|
||||||
MOCK_TURN_ON = {
|
MOCK_TURN_ON = {
|
||||||
"service": "switch.turn_on",
|
"service": "switch.turn_on",
|
||||||
"data": {"entity_id": "switch.test"},
|
"data": {"entity_id": "switch.test"},
|
||||||
}
|
}
|
||||||
MOCK_NAME = "dummy"
|
MOCK_ENTITY_ID = "media_player.arcam_fmj_127_0_0_1_zone_1"
|
||||||
MOCK_UUID = "1234"
|
MOCK_UUID = "456789abcdef"
|
||||||
MOCK_ENTITY_ID = "media_player.arcam_fmj_127_0_0_1_1234_1"
|
MOCK_UDN = f"uuid:01234567-89ab-cdef-0123-{MOCK_UUID}"
|
||||||
MOCK_CONFIG = DEVICE_SCHEMA({CONF_HOST: MOCK_HOST, CONF_PORT: MOCK_PORT})
|
MOCK_NAME = f"{DEFAULT_NAME} ({MOCK_HOST})"
|
||||||
|
MOCK_CONFIG_ENTRY = {CONF_HOST: MOCK_HOST, CONF_PORT: MOCK_PORT}
|
||||||
|
|
||||||
@pytest.fixture(name="config")
|
|
||||||
def config_fixture():
|
|
||||||
"""Create hass config fixture."""
|
|
||||||
return {DOMAIN: [{CONF_HOST: MOCK_HOST, CONF_PORT: MOCK_PORT}]}
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(name="client")
|
@pytest.fixture(name="client")
|
||||||
@ -75,7 +69,7 @@ def state_fixture(state_1):
|
|||||||
@pytest.fixture(name="player")
|
@pytest.fixture(name="player")
|
||||||
def player_fixture(hass, state):
|
def player_fixture(hass, state):
|
||||||
"""Get standard player."""
|
"""Get standard player."""
|
||||||
player = ArcamFmj(state, MOCK_UUID, MOCK_NAME, None)
|
player = ArcamFmj(MOCK_NAME, state, MOCK_UUID)
|
||||||
player.entity_id = MOCK_ENTITY_ID
|
player.entity_id = MOCK_ENTITY_ID
|
||||||
player.hass = hass
|
player.hass = hass
|
||||||
player.async_write_ha_state = Mock()
|
player.async_write_ha_state = Mock()
|
||||||
@ -83,8 +77,12 @@ def player_fixture(hass, state):
|
|||||||
|
|
||||||
|
|
||||||
@pytest.fixture(name="player_setup")
|
@pytest.fixture(name="player_setup")
|
||||||
async def player_setup_fixture(hass, config, state_1, state_2, client):
|
async def player_setup_fixture(hass, state_1, state_2, client):
|
||||||
"""Get standard player."""
|
"""Get standard player."""
|
||||||
|
config_entry = MockConfigEntry(
|
||||||
|
domain="arcam_fmj", data=MOCK_CONFIG_ENTRY, title=MOCK_NAME
|
||||||
|
)
|
||||||
|
config_entry.add_to_hass(hass)
|
||||||
|
|
||||||
def state_mock(cli, zone):
|
def state_mock(cli, zone):
|
||||||
if zone == 1:
|
if zone == 1:
|
||||||
@ -95,6 +93,6 @@ async def player_setup_fixture(hass, config, state_1, state_2, client):
|
|||||||
with patch("homeassistant.components.arcam_fmj.Client", return_value=client), patch(
|
with patch("homeassistant.components.arcam_fmj.Client", return_value=client), patch(
|
||||||
"homeassistant.components.arcam_fmj.media_player.State", side_effect=state_mock
|
"homeassistant.components.arcam_fmj.media_player.State", side_effect=state_mock
|
||||||
), patch("homeassistant.components.arcam_fmj._run_client", return_value=None):
|
), patch("homeassistant.components.arcam_fmj._run_client", return_value=None):
|
||||||
assert await async_setup_component(hass, "arcam_fmj", config)
|
assert await hass.config_entries.async_setup(config_entry.entry_id)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
yield MOCK_ENTITY_ID
|
yield MOCK_ENTITY_ID
|
||||||
|
@ -1,37 +1,182 @@
|
|||||||
"""Tests for the Arcam FMJ config flow module."""
|
"""Tests for the Arcam FMJ config flow module."""
|
||||||
|
|
||||||
|
from arcam.fmj.client import ConnectionFailed
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from homeassistant import data_entry_flow
|
from homeassistant import data_entry_flow
|
||||||
from homeassistant.components.arcam_fmj.config_flow import ArcamFmjFlowHandler
|
from homeassistant.components import ssdp
|
||||||
from homeassistant.components.arcam_fmj.const import DOMAIN
|
from homeassistant.components.arcam_fmj.config_flow import get_entry_client
|
||||||
|
from homeassistant.components.arcam_fmj.const import DOMAIN, DOMAIN_DATA_ENTRIES
|
||||||
|
from homeassistant.config_entries import SOURCE_SSDP, SOURCE_USER
|
||||||
|
from homeassistant.const import CONF_HOST, CONF_PORT, CONF_SOURCE
|
||||||
|
|
||||||
from .conftest import MOCK_CONFIG, MOCK_NAME
|
from .conftest import (
|
||||||
|
MOCK_CONFIG_ENTRY,
|
||||||
|
MOCK_HOST,
|
||||||
|
MOCK_NAME,
|
||||||
|
MOCK_PORT,
|
||||||
|
MOCK_UDN,
|
||||||
|
MOCK_UUID,
|
||||||
|
)
|
||||||
|
|
||||||
|
from tests.async_mock import AsyncMock, patch
|
||||||
from tests.common import MockConfigEntry
|
from tests.common import MockConfigEntry
|
||||||
|
|
||||||
|
MOCK_UPNP_DEVICE = f"""
|
||||||
|
<root xmlns="urn:schemas-upnp-org:device-1-0">
|
||||||
|
<device>
|
||||||
|
<UDN>{MOCK_UDN}</UDN>
|
||||||
|
</device>
|
||||||
|
</root>
|
||||||
|
"""
|
||||||
|
|
||||||
@pytest.fixture(name="config_entry")
|
MOCK_UPNP_LOCATION = f"http://{MOCK_HOST}:8080/dd.xml"
|
||||||
def config_entry_fixture():
|
|
||||||
"""Create a mock Arcam config entry."""
|
MOCK_DISCOVER = {
|
||||||
return MockConfigEntry(domain=DOMAIN, data=MOCK_CONFIG, title=MOCK_NAME)
|
ssdp.ATTR_UPNP_MANUFACTURER: "ARCAM",
|
||||||
|
ssdp.ATTR_UPNP_MODEL_NAME: " ",
|
||||||
|
ssdp.ATTR_UPNP_MODEL_NUMBER: "AVR450, AVR750",
|
||||||
|
ssdp.ATTR_UPNP_FRIENDLY_NAME: f"Arcam media client {MOCK_UUID}",
|
||||||
|
ssdp.ATTR_UPNP_SERIAL: "12343",
|
||||||
|
ssdp.ATTR_SSDP_LOCATION: f"http://{MOCK_HOST}:8080/dd.xml",
|
||||||
|
ssdp.ATTR_UPNP_UDN: MOCK_UDN,
|
||||||
|
ssdp.ATTR_UPNP_DEVICE_TYPE: "urn:schemas-upnp-org:device:MediaRenderer:1",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
async def test_single_import_only(hass, config_entry):
|
@pytest.fixture(name="dummy_client", autouse=True)
|
||||||
"""Test form is shown when host not provided."""
|
def dummy_client_fixture(hass):
|
||||||
config_entry.add_to_hass(hass)
|
"""Mock out the real client."""
|
||||||
flow = ArcamFmjFlowHandler()
|
with patch("homeassistant.components.arcam_fmj.config_flow.Client") as client:
|
||||||
flow.hass = hass
|
client.return_value.start.side_effect = AsyncMock(return_value=None)
|
||||||
result = await flow.async_step_import(MOCK_CONFIG)
|
client.return_value.stop.side_effect = AsyncMock(return_value=None)
|
||||||
assert result["type"] == data_entry_flow.RESULT_TYPE_ABORT
|
yield client.return_value
|
||||||
assert result["reason"] == "already_setup"
|
|
||||||
|
|
||||||
|
|
||||||
async def test_import(hass):
|
async def test_ssdp(hass, dummy_client):
|
||||||
"""Test form is shown when host not provided."""
|
"""Test a ssdp import flow."""
|
||||||
flow = ArcamFmjFlowHandler()
|
result = await hass.config_entries.flow.async_init(
|
||||||
flow.hass = hass
|
DOMAIN, context={CONF_SOURCE: SOURCE_SSDP}, data=MOCK_DISCOVER,
|
||||||
result = await flow.async_step_import(MOCK_CONFIG)
|
)
|
||||||
|
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
|
||||||
|
assert result["step_id"] == "confirm"
|
||||||
|
|
||||||
|
result = await hass.config_entries.flow.async_configure(result["flow_id"], {})
|
||||||
assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
|
assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
|
||||||
assert result["title"] == "Arcam FMJ"
|
assert result["title"] == f"Arcam FMJ ({MOCK_HOST})"
|
||||||
assert result["data"] == MOCK_CONFIG
|
assert result["data"] == MOCK_CONFIG_ENTRY
|
||||||
|
|
||||||
|
|
||||||
|
async def test_ssdp_abort(hass):
|
||||||
|
"""Test a ssdp import flow."""
|
||||||
|
entry = MockConfigEntry(
|
||||||
|
domain=DOMAIN, data=MOCK_CONFIG_ENTRY, title=MOCK_NAME, unique_id=MOCK_UUID
|
||||||
|
)
|
||||||
|
entry.add_to_hass(hass)
|
||||||
|
|
||||||
|
result = await hass.config_entries.flow.async_init(
|
||||||
|
DOMAIN, context={CONF_SOURCE: SOURCE_SSDP}, data=MOCK_DISCOVER,
|
||||||
|
)
|
||||||
|
assert result["type"] == data_entry_flow.RESULT_TYPE_ABORT
|
||||||
|
assert result["reason"] == "already_configured"
|
||||||
|
|
||||||
|
|
||||||
|
async def test_ssdp_unable_to_connect(hass, dummy_client):
|
||||||
|
"""Test a ssdp import flow."""
|
||||||
|
dummy_client.start.side_effect = AsyncMock(side_effect=ConnectionFailed)
|
||||||
|
|
||||||
|
result = await hass.config_entries.flow.async_init(
|
||||||
|
DOMAIN, context={CONF_SOURCE: SOURCE_SSDP}, data=MOCK_DISCOVER,
|
||||||
|
)
|
||||||
|
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
|
||||||
|
assert result["step_id"] == "confirm"
|
||||||
|
|
||||||
|
result = await hass.config_entries.flow.async_configure(result["flow_id"], {})
|
||||||
|
assert result["type"] == data_entry_flow.RESULT_TYPE_ABORT
|
||||||
|
assert result["reason"] == "unable_to_connect"
|
||||||
|
|
||||||
|
|
||||||
|
async def test_ssdp_update(hass):
|
||||||
|
"""Test a ssdp import flow."""
|
||||||
|
entry = MockConfigEntry(
|
||||||
|
domain=DOMAIN,
|
||||||
|
data={CONF_HOST: "old_host", CONF_PORT: MOCK_PORT},
|
||||||
|
title=MOCK_NAME,
|
||||||
|
unique_id=MOCK_UUID,
|
||||||
|
)
|
||||||
|
entry.add_to_hass(hass)
|
||||||
|
|
||||||
|
result = await hass.config_entries.flow.async_init(
|
||||||
|
DOMAIN, context={CONF_SOURCE: SOURCE_SSDP}, data=MOCK_DISCOVER,
|
||||||
|
)
|
||||||
|
assert result["type"] == data_entry_flow.RESULT_TYPE_ABORT
|
||||||
|
assert result["reason"] == "already_configured"
|
||||||
|
|
||||||
|
assert entry.data[CONF_HOST] == MOCK_HOST
|
||||||
|
|
||||||
|
|
||||||
|
async def test_user(hass, aioclient_mock):
|
||||||
|
"""Test a manual user configuration flow."""
|
||||||
|
|
||||||
|
result = await hass.config_entries.flow.async_init(
|
||||||
|
DOMAIN, context={CONF_SOURCE: SOURCE_USER}, data=None,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
|
||||||
|
assert result["step_id"] == "user"
|
||||||
|
|
||||||
|
user_input = {
|
||||||
|
CONF_HOST: MOCK_HOST,
|
||||||
|
CONF_PORT: MOCK_PORT,
|
||||||
|
}
|
||||||
|
|
||||||
|
aioclient_mock.get(MOCK_UPNP_LOCATION, text=MOCK_UPNP_DEVICE)
|
||||||
|
result = await hass.config_entries.flow.async_configure(
|
||||||
|
result["flow_id"], user_input
|
||||||
|
)
|
||||||
|
assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
|
||||||
|
assert result["title"] == f"Arcam FMJ ({MOCK_HOST})"
|
||||||
|
assert result["data"] == MOCK_CONFIG_ENTRY
|
||||||
|
assert result["result"].unique_id == MOCK_UUID
|
||||||
|
|
||||||
|
|
||||||
|
async def test_invalid_ssdp(hass, aioclient_mock):
|
||||||
|
"""Test a a config flow where ssdp fails."""
|
||||||
|
user_input = {
|
||||||
|
CONF_HOST: MOCK_HOST,
|
||||||
|
CONF_PORT: MOCK_PORT,
|
||||||
|
}
|
||||||
|
|
||||||
|
aioclient_mock.get(MOCK_UPNP_LOCATION, text="")
|
||||||
|
result = await hass.config_entries.flow.async_init(
|
||||||
|
DOMAIN, context={CONF_SOURCE: SOURCE_USER}, data=user_input,
|
||||||
|
)
|
||||||
|
assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
|
||||||
|
assert result["title"] == f"Arcam FMJ ({MOCK_HOST})"
|
||||||
|
assert result["data"] == MOCK_CONFIG_ENTRY
|
||||||
|
assert result["result"].unique_id is None
|
||||||
|
|
||||||
|
|
||||||
|
async def test_user_wrong(hass, aioclient_mock):
|
||||||
|
"""Test a manual user configuration flow with no ssdp response."""
|
||||||
|
user_input = {
|
||||||
|
CONF_HOST: MOCK_HOST,
|
||||||
|
CONF_PORT: MOCK_PORT,
|
||||||
|
}
|
||||||
|
|
||||||
|
aioclient_mock.get(MOCK_UPNP_LOCATION, status=404)
|
||||||
|
result = await hass.config_entries.flow.async_init(
|
||||||
|
DOMAIN, context={CONF_SOURCE: SOURCE_USER}, data=user_input,
|
||||||
|
)
|
||||||
|
assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
|
||||||
|
assert result["title"] == f"Arcam FMJ ({MOCK_HOST})"
|
||||||
|
assert result["result"].unique_id is None
|
||||||
|
|
||||||
|
|
||||||
|
async def test_get_entry_client(hass):
|
||||||
|
"""Test helper for configuration."""
|
||||||
|
entry = MockConfigEntry(
|
||||||
|
domain=DOMAIN, data=MOCK_CONFIG_ENTRY, title=MOCK_NAME, unique_id=MOCK_UUID
|
||||||
|
)
|
||||||
|
hass.data[DOMAIN_DATA_ENTRIES] = {entry.entry_id: "dummy"}
|
||||||
|
assert get_entry_client(hass, entry) == "dummy"
|
||||||
|
@ -4,10 +4,14 @@ from math import isclose
|
|||||||
from arcam.fmj import DecodeMode2CH, DecodeModeMCH, IncomingAudioFormat, SourceCodes
|
from arcam.fmj import DecodeMode2CH, DecodeModeMCH, IncomingAudioFormat, SourceCodes
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from homeassistant.components.media_player.const import MEDIA_TYPE_MUSIC
|
from homeassistant.components.media_player.const import (
|
||||||
from homeassistant.core import HomeAssistant
|
ATTR_INPUT_SOURCE,
|
||||||
|
MEDIA_TYPE_MUSIC,
|
||||||
|
SERVICE_SELECT_SOURCE,
|
||||||
|
)
|
||||||
|
from homeassistant.const import ATTR_ENTITY_ID
|
||||||
|
|
||||||
from .conftest import MOCK_ENTITY_ID, MOCK_HOST, MOCK_NAME, MOCK_PORT, MOCK_UUID
|
from .conftest import MOCK_HOST, MOCK_NAME, MOCK_PORT, MOCK_UUID
|
||||||
|
|
||||||
from tests.async_mock import ANY, MagicMock, Mock, PropertyMock, patch
|
from tests.async_mock import ANY, MagicMock, Mock, PropertyMock, patch
|
||||||
|
|
||||||
@ -27,8 +31,9 @@ async def test_properties(player, state):
|
|||||||
"""Test standard properties."""
|
"""Test standard properties."""
|
||||||
assert player.unique_id == f"{MOCK_UUID}-1"
|
assert player.unique_id == f"{MOCK_UUID}-1"
|
||||||
assert player.device_info == {
|
assert player.device_info == {
|
||||||
"identifiers": {("arcam_fmj", MOCK_HOST, MOCK_PORT)},
|
"name": f"Arcam FMJ ({MOCK_HOST})",
|
||||||
"model": "FMJ",
|
"identifiers": {("arcam_fmj", MOCK_UUID), ("arcam_fmj", MOCK_HOST, MOCK_PORT)},
|
||||||
|
"model": "Arcam FMJ AVR",
|
||||||
"manufacturer": "Arcam",
|
"manufacturer": "Arcam",
|
||||||
}
|
}
|
||||||
assert not player.should_poll
|
assert not player.should_poll
|
||||||
@ -55,12 +60,12 @@ async def test_powered_on(player, state):
|
|||||||
|
|
||||||
|
|
||||||
async def test_supported_features(player, state):
|
async def test_supported_features(player, state):
|
||||||
"""Test support when turn on service exist."""
|
"""Test supported features."""
|
||||||
data = await update(player)
|
data = await update(player)
|
||||||
assert data.attributes["supported_features"] == 69004
|
assert data.attributes["supported_features"] == 69004
|
||||||
|
|
||||||
|
|
||||||
async def test_turn_on_without_service(player, state):
|
async def test_turn_on(player, state):
|
||||||
"""Test turn on service."""
|
"""Test turn on service."""
|
||||||
state.get_power.return_value = None
|
state.get_power.return_value = None
|
||||||
await player.async_turn_on()
|
await player.async_turn_on()
|
||||||
@ -71,29 +76,6 @@ async def test_turn_on_without_service(player, state):
|
|||||||
state.set_power.assert_called_with(True)
|
state.set_power.assert_called_with(True)
|
||||||
|
|
||||||
|
|
||||||
async def test_turn_on_with_service(hass, state):
|
|
||||||
"""Test support when turn on service exist."""
|
|
||||||
from homeassistant.components.arcam_fmj.media_player import ArcamFmj
|
|
||||||
|
|
||||||
player = ArcamFmj(state, MOCK_UUID, "dummy", MOCK_TURN_ON)
|
|
||||||
player.hass = Mock(HomeAssistant)
|
|
||||||
player.entity_id = MOCK_ENTITY_ID
|
|
||||||
with patch(
|
|
||||||
"homeassistant.components.arcam_fmj.media_player.async_call_from_config"
|
|
||||||
) as async_call_from_config:
|
|
||||||
|
|
||||||
state.get_power.return_value = None
|
|
||||||
await player.async_turn_on()
|
|
||||||
state.set_power.assert_not_called()
|
|
||||||
async_call_from_config.assert_called_with(
|
|
||||||
player.hass,
|
|
||||||
MOCK_TURN_ON,
|
|
||||||
variables=None,
|
|
||||||
blocking=True,
|
|
||||||
validate_config=False,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
async def test_turn_off(player, state):
|
async def test_turn_off(player, state):
|
||||||
"""Test command to turn off."""
|
"""Test command to turn off."""
|
||||||
await player.async_turn_off()
|
await player.async_turn_off()
|
||||||
@ -110,7 +92,7 @@ async def test_mute_volume(player, state, mute):
|
|||||||
|
|
||||||
async def test_name(player):
|
async def test_name(player):
|
||||||
"""Test name."""
|
"""Test name."""
|
||||||
assert player.name == MOCK_NAME
|
assert player.name == f"{MOCK_NAME} - Zone: 1"
|
||||||
|
|
||||||
|
|
||||||
async def test_update(player, state):
|
async def test_update(player, state):
|
||||||
@ -138,9 +120,15 @@ async def test_2ch(player, state, fmt, result):
|
|||||||
"source, value",
|
"source, value",
|
||||||
[("PVR", SourceCodes.PVR), ("BD", SourceCodes.BD), ("INVALID", None)],
|
[("PVR", SourceCodes.PVR), ("BD", SourceCodes.BD), ("INVALID", None)],
|
||||||
)
|
)
|
||||||
async def test_select_source(player, state, source, value):
|
async def test_select_source(hass, player_setup, state, source, value):
|
||||||
"""Test selection of source."""
|
"""Test selection of source."""
|
||||||
await player.async_select_source(source)
|
await hass.services.async_call(
|
||||||
|
"media_player",
|
||||||
|
SERVICE_SELECT_SOURCE,
|
||||||
|
service_data={ATTR_ENTITY_ID: player_setup, ATTR_INPUT_SOURCE: source},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
|
||||||
if value:
|
if value:
|
||||||
state.set_source.assert_called_with(value)
|
state.set_source.assert_called_with(value)
|
||||||
else:
|
else:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user