Skip to content

Commit

Permalink
Add config flow to bluesound
Browse files Browse the repository at this point in the history
  • Loading branch information
LouisChrist committed May 11, 2024
1 parent a37d274 commit a64e8ee
Show file tree
Hide file tree
Showing 12 changed files with 152 additions and 43 deletions.
3 changes: 2 additions & 1 deletion .coveragerc
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,8 @@ omit =
homeassistant/components/blinksticklight/light.py
homeassistant/components/blockchain/sensor.py
homeassistant/components/bloomsky/*
homeassistant/components/bluesound/*
homeassistant/components/bluesound/__init__.py
homeassistant/components/bluesound/media_player.py
homeassistant/components/bluetooth_tracker/*
homeassistant/components/bmw_connected_drive/__init__.py
homeassistant/components/bmw_connected_drive/binary_sensor.py
Expand Down
1 change: 1 addition & 0 deletions CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,7 @@ build.json @home-assistant/supervisor
/homeassistant/components/blueprint/ @home-assistant/core
/tests/components/blueprint/ @home-assistant/core
/homeassistant/components/bluesound/ @thrawnarn
/tests/components/bluesound/ @thrawnarn
/homeassistant/components/bluetooth/ @bdraco
/tests/components/bluetooth/ @bdraco
/homeassistant/components/bluetooth_adapters/ @bdraco
Expand Down
27 changes: 27 additions & 0 deletions homeassistant/components/bluesound/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1,28 @@
"""The bluesound component."""

from homeassistant.config_entries import ConfigEntry
from homeassistant.const import Platform
from homeassistant.core import HomeAssistant
from homeassistant.helpers import config_validation as cv
from homeassistant.helpers.typing import ConfigType

from .const import DOMAIN
from .media_player import setup_services

CONFIG_SCHEMA = cv.config_entry_only_config_schema(DOMAIN)


async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> bool:
"""Set up the Bluesound entry."""
await hass.config_entries.async_forward_entry_setup(
config_entry, Platform.MEDIA_PLAYER
)

return True


async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
"""Set up the Bluesound."""
setup_services(hass)

return True
42 changes: 42 additions & 0 deletions homeassistant/components/bluesound/config_flow.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
"""Config flow for bluesound."""

import logging
from typing import Any

import voluptuous as vol

from homeassistant import config_entries
from homeassistant.config_entries import ConfigFlowResult
from homeassistant.const import CONF_HOST, CONF_NAME, CONF_PORT

from .const import DOMAIN

_LOGGER = logging.getLogger(__name__)


class BluesoundConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
"""Bluesound config flow."""

VERSION = 1
MINOR_VERSION = 1

async def async_step_user(
self, user_input: dict[str, Any] | None = None
) -> ConfigFlowResult:
"""Handle a flow initiated by the user."""
if user_input is not None:
return self.async_create_entry(
title=user_input[CONF_NAME],
data=user_input,
)

return self.async_show_form(
step_id="user",
data_schema=vol.Schema(
{
vol.Required(CONF_NAME, default="Bluesound"): str,
vol.Required(CONF_HOST, description="host"): str,
vol.Optional(CONF_PORT, default=11000): int,
}
),
)
1 change: 1 addition & 0 deletions homeassistant/components/bluesound/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"domain": "bluesound",
"name": "Bluesound",
"codeowners": ["@thrawnarn"],
"config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/bluesound",
"iot_class": "local_polling",
"requirements": ["xmltodict==0.13.0"]
Expand Down
55 changes: 14 additions & 41 deletions homeassistant/components/bluesound/media_player.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,19 +18,17 @@

from homeassistant.components import media_source
from homeassistant.components.media_player import (
PLATFORM_SCHEMA,
BrowseMedia,
MediaPlayerEntity,
MediaPlayerEntityFeature,
MediaPlayerState,
MediaType,
async_process_play_media_url,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import (
ATTR_ENTITY_ID,
CONF_HOST,
CONF_HOSTS,
CONF_NAME,
CONF_PORT,
EVENT_HOMEASSISTANT_START,
EVENT_HOMEASSISTANT_STOP,
Expand All @@ -41,7 +39,6 @@
from homeassistant.helpers.device_registry import format_mac
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.event import async_track_time_interval
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
from homeassistant.util import Throttle
import homeassistant.util.dt as dt_util

Expand Down Expand Up @@ -70,21 +67,6 @@
UPDATE_PRESETS_INTERVAL = timedelta(minutes=30)
UPDATE_SERVICES_INTERVAL = timedelta(minutes=30)

PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
{
vol.Optional(CONF_HOSTS): vol.All(
cv.ensure_list,
[
{
vol.Required(CONF_HOST): cv.string,
vol.Optional(CONF_NAME): cv.string,
vol.Optional(CONF_PORT, default=DEFAULT_PORT): cv.port,
}
],
)
}
)

BS_SCHEMA = vol.Schema({vol.Optional(ATTR_ENTITY_ID): cv.entity_ids})

BS_JOIN_SCHEMA = BS_SCHEMA.extend({vol.Required(ATTR_MASTER): cv.entity_id})
Expand Down Expand Up @@ -141,34 +123,25 @@ def _add_player_cb():
hass.bus.async_listen_once(EVENT_HOMEASSISTANT_START, _init_player)


async def async_setup_platform(
async def async_setup_entry(
hass: HomeAssistant,
config: ConfigType,
config_entry: ConfigEntry,
async_add_entities: AddEntitiesCallback,
discovery_info: DiscoveryInfoType | None = None,
) -> None:
"""Set up the Bluesound platforms."""
"""Set up the Bluesound entry."""
if DATA_BLUESOUND not in hass.data:
hass.data[DATA_BLUESOUND] = []

if discovery_info:
_add_player(
hass,
async_add_entities,
discovery_info.get(CONF_HOST),
discovery_info.get(CONF_PORT),
)
return

if hosts := config.get(CONF_HOSTS):
for host in hosts:
_add_player(
hass,
async_add_entities,
host.get(CONF_HOST),
host.get(CONF_PORT),
host.get(CONF_NAME),
)
_add_player(
hass,
async_add_entities,
config_entry.data.get(CONF_HOST),
config_entry.data.get(CONF_PORT),
)


def setup_services(hass: HomeAssistant):
"""Set up services for Bluesound component."""

async def async_service_handler(service: ServiceCall) -> None:
"""Map services to method of Bluesound devices."""
Expand Down
11 changes: 11 additions & 0 deletions homeassistant/components/bluesound/strings.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,15 @@
{
"config": {
"step": {
"user": {
"data": {
"host": "[%key:common::config_flow::data::host%]",
"port": "[%key:common::config_flow::data::port%]",
"name": "[%key:common::config_flow::data::name%]"
}
}
}
},
"services": {
"join": {
"name": "Join",
Expand Down
1 change: 1 addition & 0 deletions homeassistant/generated/config_flows.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@
"blink",
"blue_current",
"bluemaestro",
"bluesound",
"bluetooth",
"bmw_connected_drive",
"bond",
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/generated/integrations.json
Original file line number Diff line number Diff line change
Expand Up @@ -708,7 +708,7 @@
"bluesound": {
"name": "Bluesound",
"integration_type": "hub",
"config_flow": false,
"config_flow": true,
"iot_class": "local_polling"
},
"bluetooth": {
Expand Down
1 change: 1 addition & 0 deletions tests/components/bluesound/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"""Tests for the Bluesound integration."""
15 changes: 15 additions & 0 deletions tests/components/bluesound/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
"""Common fixtures for the Bluesound tests."""

from collections.abc import Generator
from unittest.mock import AsyncMock, patch

import pytest


@pytest.fixture
def mock_setup_entry() -> Generator[AsyncMock, None, None]:
"""Override async_setup_entry."""
with patch(
"homeassistant.components.bluesound.async_setup_entry", return_value=True
) as mock_setup_entry:
yield mock_setup_entry
36 changes: 36 additions & 0 deletions tests/components/bluesound/test_config_flow.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
"""Test the Bluesound config flow."""

from unittest.mock import AsyncMock

from homeassistant import config_entries
from homeassistant.components.bluesound.const import DOMAIN
from homeassistant.const import CONF_HOST, CONF_NAME, CONF_PORT
from homeassistant.core import HomeAssistant
from homeassistant.data_entry_flow import FlowResultType


async def test_form(hass: HomeAssistant, mock_setup_entry: AsyncMock) -> None:
"""Test we get the form."""
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": config_entries.SOURCE_USER}
)
assert result["type"] == FlowResultType.FORM
assert result["errors"] is None

result = await hass.config_entries.flow.async_configure(
result["flow_id"],
{
CONF_HOST: "1.1.1.1",
CONF_NAME: "test-name",
},
)
await hass.async_block_till_done()

assert result["type"] == FlowResultType.CREATE_ENTRY
assert result["title"] == "test-name"
assert result["data"] == {
CONF_HOST: "1.1.1.1",
CONF_PORT: 11000,
CONF_NAME: "test-name",
}
assert len(mock_setup_entry.mock_calls) == 1

0 comments on commit a64e8ee

Please sign in to comment.