mirror of
https://github.com/home-assistant/core.git
synced 2025-07-19 19:27:45 +00:00
Refactor and improve anthemav (#75852)
This commit is contained in:
parent
a1d96175a8
commit
bbd7041a73
@ -6,8 +6,8 @@ import logging
|
|||||||
import anthemav
|
import anthemav
|
||||||
|
|
||||||
from homeassistant.config_entries import ConfigEntry
|
from homeassistant.config_entries import ConfigEntry
|
||||||
from homeassistant.const import CONF_HOST, CONF_NAME, CONF_PORT, Platform
|
from homeassistant.const import CONF_HOST, CONF_PORT, EVENT_HOMEASSISTANT_STOP, Platform
|
||||||
from homeassistant.core import HomeAssistant, callback
|
from homeassistant.core import Event, HomeAssistant, callback
|
||||||
from homeassistant.exceptions import ConfigEntryNotReady
|
from homeassistant.exceptions import ConfigEntryNotReady
|
||||||
from homeassistant.helpers.dispatcher import async_dispatcher_send
|
from homeassistant.helpers.dispatcher import async_dispatcher_send
|
||||||
|
|
||||||
@ -25,7 +25,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
|||||||
def async_anthemav_update_callback(message):
|
def async_anthemav_update_callback(message):
|
||||||
"""Receive notification from transport that new data exists."""
|
"""Receive notification from transport that new data exists."""
|
||||||
_LOGGER.debug("Received update callback from AVR: %s", message)
|
_LOGGER.debug("Received update callback from AVR: %s", message)
|
||||||
async_dispatcher_send(hass, f"{ANTHEMAV_UDATE_SIGNAL}_{entry.data[CONF_NAME]}")
|
async_dispatcher_send(hass, f"{ANTHEMAV_UDATE_SIGNAL}_{entry.entry_id}")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
avr = await anthemav.Connection.create(
|
avr = await anthemav.Connection.create(
|
||||||
@ -41,6 +41,14 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
|||||||
|
|
||||||
hass.config_entries.async_setup_platforms(entry, PLATFORMS)
|
hass.config_entries.async_setup_platforms(entry, PLATFORMS)
|
||||||
|
|
||||||
|
@callback
|
||||||
|
def close_avr(event: Event) -> None:
|
||||||
|
avr.close()
|
||||||
|
|
||||||
|
entry.async_on_unload(
|
||||||
|
hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, close_avr)
|
||||||
|
)
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
@ -85,17 +85,17 @@ async def async_setup_entry(
|
|||||||
) -> None:
|
) -> None:
|
||||||
"""Set up entry."""
|
"""Set up entry."""
|
||||||
name = config_entry.data[CONF_NAME]
|
name = config_entry.data[CONF_NAME]
|
||||||
macaddress = config_entry.data[CONF_MAC]
|
mac_address = config_entry.data[CONF_MAC]
|
||||||
model = config_entry.data[CONF_MODEL]
|
model = config_entry.data[CONF_MODEL]
|
||||||
|
|
||||||
avr = hass.data[DOMAIN][config_entry.entry_id]
|
avr = hass.data[DOMAIN][config_entry.entry_id]
|
||||||
|
|
||||||
device = AnthemAVR(avr, name, macaddress, model)
|
entity = AnthemAVR(avr, name, mac_address, model, config_entry.entry_id)
|
||||||
|
|
||||||
_LOGGER.debug("dump_devicedata: %s", device.dump_avrdata)
|
_LOGGER.debug("Device data dump: %s", entity.dump_avrdata)
|
||||||
_LOGGER.debug("dump_conndata: %s", avr.dump_conndata)
|
_LOGGER.debug("Connection data dump: %s", avr.dump_conndata)
|
||||||
|
|
||||||
async_add_entities([device])
|
async_add_entities([entity])
|
||||||
|
|
||||||
|
|
||||||
class AnthemAVR(MediaPlayerEntity):
|
class AnthemAVR(MediaPlayerEntity):
|
||||||
@ -110,14 +110,17 @@ class AnthemAVR(MediaPlayerEntity):
|
|||||||
| MediaPlayerEntityFeature.SELECT_SOURCE
|
| MediaPlayerEntityFeature.SELECT_SOURCE
|
||||||
)
|
)
|
||||||
|
|
||||||
def __init__(self, avr: Connection, name: str, macaddress: str, model: str) -> None:
|
def __init__(
|
||||||
|
self, avr: Connection, name: str, mac_address: str, model: str, entry_id: str
|
||||||
|
) -> None:
|
||||||
"""Initialize entity with transport."""
|
"""Initialize entity with transport."""
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.avr = avr
|
self.avr = avr
|
||||||
|
self._entry_id = entry_id
|
||||||
self._attr_name = name
|
self._attr_name = name
|
||||||
self._attr_unique_id = macaddress
|
self._attr_unique_id = mac_address
|
||||||
self._attr_device_info = DeviceInfo(
|
self._attr_device_info = DeviceInfo(
|
||||||
identifiers={(DOMAIN, macaddress)},
|
identifiers={(DOMAIN, mac_address)},
|
||||||
name=name,
|
name=name,
|
||||||
manufacturer=MANUFACTURER,
|
manufacturer=MANUFACTURER,
|
||||||
model=model,
|
model=model,
|
||||||
@ -131,7 +134,7 @@ class AnthemAVR(MediaPlayerEntity):
|
|||||||
self.async_on_remove(
|
self.async_on_remove(
|
||||||
async_dispatcher_connect(
|
async_dispatcher_connect(
|
||||||
self.hass,
|
self.hass,
|
||||||
f"{ANTHEMAV_UDATE_SIGNAL}_{self._attr_name}",
|
f"{ANTHEMAV_UDATE_SIGNAL}_{self._entry_id}",
|
||||||
self.async_write_ha_state,
|
self.async_write_ha_state,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -3,6 +3,11 @@ from unittest.mock import AsyncMock, MagicMock, patch
|
|||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
from homeassistant.components.anthemav.const import CONF_MODEL, DOMAIN
|
||||||
|
from homeassistant.const import CONF_HOST, CONF_MAC, CONF_NAME, CONF_PORT
|
||||||
|
|
||||||
|
from tests.common import MockConfigEntry
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def mock_anthemav() -> AsyncMock:
|
def mock_anthemav() -> AsyncMock:
|
||||||
@ -14,6 +19,7 @@ def mock_anthemav() -> AsyncMock:
|
|||||||
avr.close = MagicMock()
|
avr.close = MagicMock()
|
||||||
avr.protocol.input_list = []
|
avr.protocol.input_list = []
|
||||||
avr.protocol.audio_listening_mode_list = []
|
avr.protocol.audio_listening_mode_list = []
|
||||||
|
avr.protocol.power = False
|
||||||
return avr
|
return avr
|
||||||
|
|
||||||
|
|
||||||
@ -26,3 +32,19 @@ def mock_connection_create(mock_anthemav: AsyncMock) -> AsyncMock:
|
|||||||
return_value=mock_anthemav,
|
return_value=mock_anthemav,
|
||||||
) as mock:
|
) as mock:
|
||||||
yield mock
|
yield mock
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def mock_config_entry() -> MockConfigEntry:
|
||||||
|
"""Return the default mocked config entry."""
|
||||||
|
return MockConfigEntry(
|
||||||
|
domain=DOMAIN,
|
||||||
|
data={
|
||||||
|
CONF_HOST: "1.1.1.1",
|
||||||
|
CONF_PORT: 14999,
|
||||||
|
CONF_NAME: "Anthem AV",
|
||||||
|
CONF_MAC: "00:00:00:00:00:01",
|
||||||
|
CONF_MODEL: "MRX 520",
|
||||||
|
},
|
||||||
|
unique_id="00:00:00:00:00:01",
|
||||||
|
)
|
||||||
|
@ -2,19 +2,22 @@
|
|||||||
from unittest.mock import AsyncMock, patch
|
from unittest.mock import AsyncMock, patch
|
||||||
|
|
||||||
from anthemav.device_error import DeviceError
|
from anthemav.device_error import DeviceError
|
||||||
|
import pytest
|
||||||
|
|
||||||
from homeassistant import config_entries
|
|
||||||
from homeassistant.components.anthemav.const import DOMAIN
|
from homeassistant.components.anthemav.const import DOMAIN
|
||||||
|
from homeassistant.config_entries import SOURCE_IMPORT, SOURCE_USER
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.data_entry_flow import FlowResultType
|
from homeassistant.data_entry_flow import FlowResultType
|
||||||
|
|
||||||
|
from tests.common import MockConfigEntry
|
||||||
|
|
||||||
|
|
||||||
async def test_form_with_valid_connection(
|
async def test_form_with_valid_connection(
|
||||||
hass: HomeAssistant, mock_connection_create: AsyncMock, mock_anthemav: AsyncMock
|
hass: HomeAssistant, mock_connection_create: AsyncMock, mock_anthemav: AsyncMock
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test we get the form."""
|
"""Test we get the form."""
|
||||||
result = await hass.config_entries.flow.async_init(
|
result = await hass.config_entries.flow.async_init(
|
||||||
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
DOMAIN, context={"source": SOURCE_USER}
|
||||||
)
|
)
|
||||||
assert result["type"] == FlowResultType.FORM
|
assert result["type"] == FlowResultType.FORM
|
||||||
assert result["errors"] is None
|
assert result["errors"] is None
|
||||||
@ -47,7 +50,7 @@ async def test_form_with_valid_connection(
|
|||||||
async def test_form_device_info_error(hass: HomeAssistant) -> None:
|
async def test_form_device_info_error(hass: HomeAssistant) -> None:
|
||||||
"""Test we handle DeviceError from library."""
|
"""Test we handle DeviceError from library."""
|
||||||
result = await hass.config_entries.flow.async_init(
|
result = await hass.config_entries.flow.async_init(
|
||||||
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
DOMAIN, context={"source": SOURCE_USER}
|
||||||
)
|
)
|
||||||
|
|
||||||
with patch(
|
with patch(
|
||||||
@ -71,7 +74,7 @@ async def test_form_device_info_error(hass: HomeAssistant) -> None:
|
|||||||
async def test_form_cannot_connect(hass: HomeAssistant) -> None:
|
async def test_form_cannot_connect(hass: HomeAssistant) -> None:
|
||||||
"""Test we handle cannot connect error."""
|
"""Test we handle cannot connect error."""
|
||||||
result = await hass.config_entries.flow.async_init(
|
result = await hass.config_entries.flow.async_init(
|
||||||
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
DOMAIN, context={"source": SOURCE_USER}
|
||||||
)
|
)
|
||||||
|
|
||||||
with patch(
|
with patch(
|
||||||
@ -102,7 +105,7 @@ async def test_import_configuration(
|
|||||||
"name": "Anthem Av Import",
|
"name": "Anthem Av Import",
|
||||||
}
|
}
|
||||||
result = await hass.config_entries.flow.async_init(
|
result = await hass.config_entries.flow.async_init(
|
||||||
DOMAIN, context={"source": config_entries.SOURCE_IMPORT}, data=config
|
DOMAIN, context={"source": SOURCE_IMPORT}, data=config
|
||||||
)
|
)
|
||||||
|
|
||||||
assert result["type"] == FlowResultType.CREATE_ENTRY
|
assert result["type"] == FlowResultType.CREATE_ENTRY
|
||||||
@ -113,3 +116,26 @@ async def test_import_configuration(
|
|||||||
"mac": "00:00:00:00:00:01",
|
"mac": "00:00:00:00:00:01",
|
||||||
"model": "MRX 520",
|
"model": "MRX 520",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("source", [SOURCE_USER, SOURCE_IMPORT])
|
||||||
|
async def test_device_already_configured(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
mock_connection_create: AsyncMock,
|
||||||
|
mock_anthemav: AsyncMock,
|
||||||
|
mock_config_entry: MockConfigEntry,
|
||||||
|
source: str,
|
||||||
|
) -> None:
|
||||||
|
"""Test we import existing configuration."""
|
||||||
|
config = {
|
||||||
|
"host": "1.1.1.1",
|
||||||
|
"port": 14999,
|
||||||
|
}
|
||||||
|
|
||||||
|
mock_config_entry.add_to_hass(hass)
|
||||||
|
result = await hass.config_entries.flow.async_init(
|
||||||
|
DOMAIN, context={"source": source}, data=config
|
||||||
|
)
|
||||||
|
|
||||||
|
assert result.get("type") == FlowResultType.ABORT
|
||||||
|
assert result.get("reason") == "already_configured"
|
||||||
|
@ -2,28 +2,19 @@
|
|||||||
from unittest.mock import ANY, AsyncMock, patch
|
from unittest.mock import ANY, AsyncMock, patch
|
||||||
|
|
||||||
from homeassistant import config_entries
|
from homeassistant import config_entries
|
||||||
from homeassistant.components.anthemav.const import CONF_MODEL, DOMAIN
|
from homeassistant.const import STATE_OFF, STATE_ON
|
||||||
from homeassistant.const import CONF_HOST, CONF_MAC, CONF_NAME, CONF_PORT
|
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
|
|
||||||
from tests.common import MockConfigEntry
|
from tests.common import MockConfigEntry
|
||||||
|
|
||||||
|
|
||||||
async def test_load_unload_config_entry(
|
async def test_load_unload_config_entry(
|
||||||
hass: HomeAssistant, mock_connection_create: AsyncMock, mock_anthemav: AsyncMock
|
hass: HomeAssistant,
|
||||||
|
mock_connection_create: AsyncMock,
|
||||||
|
mock_anthemav: AsyncMock,
|
||||||
|
mock_config_entry: MockConfigEntry,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test load and unload AnthemAv component."""
|
"""Test load and unload AnthemAv component."""
|
||||||
mock_config_entry = MockConfigEntry(
|
|
||||||
domain=DOMAIN,
|
|
||||||
data={
|
|
||||||
CONF_HOST: "1.1.1.1",
|
|
||||||
CONF_PORT: 14999,
|
|
||||||
CONF_NAME: "Anthem AV",
|
|
||||||
CONF_MAC: "aabbccddeeff",
|
|
||||||
CONF_MODEL: "MRX 520",
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
mock_config_entry.add_to_hass(hass)
|
mock_config_entry.add_to_hass(hass)
|
||||||
await hass.config_entries.async_setup(mock_config_entry.entry_id)
|
await hass.config_entries.async_setup(mock_config_entry.entry_id)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
@ -42,18 +33,10 @@ async def test_load_unload_config_entry(
|
|||||||
mock_anthemav.close.assert_called_once()
|
mock_anthemav.close.assert_called_once()
|
||||||
|
|
||||||
|
|
||||||
async def test_config_entry_not_ready(hass: HomeAssistant) -> None:
|
async def test_config_entry_not_ready(
|
||||||
|
hass: HomeAssistant, mock_config_entry: MockConfigEntry
|
||||||
|
) -> None:
|
||||||
"""Test AnthemAV configuration entry not ready."""
|
"""Test AnthemAV configuration entry not ready."""
|
||||||
mock_config_entry = MockConfigEntry(
|
|
||||||
domain=DOMAIN,
|
|
||||||
data={
|
|
||||||
CONF_HOST: "1.1.1.1",
|
|
||||||
CONF_PORT: 14999,
|
|
||||||
CONF_NAME: "Anthem AV",
|
|
||||||
CONF_MAC: "aabbccddeeff",
|
|
||||||
CONF_MODEL: "MRX 520",
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
with patch(
|
with patch(
|
||||||
"anthemav.Connection.create",
|
"anthemav.Connection.create",
|
||||||
@ -63,3 +46,31 @@ async def test_config_entry_not_ready(hass: HomeAssistant) -> None:
|
|||||||
await hass.config_entries.async_setup(mock_config_entry.entry_id)
|
await hass.config_entries.async_setup(mock_config_entry.entry_id)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
assert mock_config_entry.state is config_entries.ConfigEntryState.SETUP_RETRY
|
assert mock_config_entry.state is config_entries.ConfigEntryState.SETUP_RETRY
|
||||||
|
|
||||||
|
|
||||||
|
async def test_anthemav_dispatcher_signal(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
mock_connection_create: AsyncMock,
|
||||||
|
mock_anthemav: AsyncMock,
|
||||||
|
mock_config_entry: MockConfigEntry,
|
||||||
|
) -> None:
|
||||||
|
"""Test send update signal to dispatcher."""
|
||||||
|
mock_config_entry.add_to_hass(hass)
|
||||||
|
await hass.config_entries.async_setup(mock_config_entry.entry_id)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
states = hass.states.get("media_player.anthem_av")
|
||||||
|
assert states
|
||||||
|
assert states.state == STATE_OFF
|
||||||
|
|
||||||
|
# change state of the AVR
|
||||||
|
mock_anthemav.protocol.power = True
|
||||||
|
|
||||||
|
# get the callback function that trigger the signal to update the state
|
||||||
|
avr_update_callback = mock_connection_create.call_args[1]["update_callback"]
|
||||||
|
avr_update_callback("power")
|
||||||
|
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
states = hass.states.get("media_player.anthem_av")
|
||||||
|
assert states.state == STATE_ON
|
||||||
|
Loading…
x
Reference in New Issue
Block a user