mirror of
https://github.com/home-assistant/core.git
synced 2025-07-22 20:57:21 +00:00
Try to automatically detect zones on first run of Monoprice integration (#35127)
This commit is contained in:
parent
16cc4aed06
commit
3fcd7866cc
@ -10,7 +10,13 @@ from homeassistant.const import CONF_PORT
|
|||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.exceptions import ConfigEntryNotReady
|
from homeassistant.exceptions import ConfigEntryNotReady
|
||||||
|
|
||||||
from .const import DOMAIN, MONOPRICE_OBJECT, UNDO_UPDATE_LISTENER
|
from .const import (
|
||||||
|
CONF_NOT_FIRST_RUN,
|
||||||
|
DOMAIN,
|
||||||
|
FIRST_RUN,
|
||||||
|
MONOPRICE_OBJECT,
|
||||||
|
UNDO_UPDATE_LISTENER,
|
||||||
|
)
|
||||||
|
|
||||||
PLATFORMS = ["media_player"]
|
PLATFORMS = ["media_player"]
|
||||||
|
|
||||||
@ -32,11 +38,20 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry):
|
|||||||
_LOGGER.error("Error connecting to Monoprice controller at %s", port)
|
_LOGGER.error("Error connecting to Monoprice controller at %s", port)
|
||||||
raise ConfigEntryNotReady
|
raise ConfigEntryNotReady
|
||||||
|
|
||||||
|
# double negative to handle absence of value
|
||||||
|
first_run = not bool(entry.data.get(CONF_NOT_FIRST_RUN))
|
||||||
|
|
||||||
|
if first_run:
|
||||||
|
hass.config_entries.async_update_entry(
|
||||||
|
entry, data={**entry.data, CONF_NOT_FIRST_RUN: True}
|
||||||
|
)
|
||||||
|
|
||||||
undo_listener = entry.add_update_listener(_update_listener)
|
undo_listener = entry.add_update_listener(_update_listener)
|
||||||
|
|
||||||
hass.data.setdefault(DOMAIN, {})[entry.entry_id] = {
|
hass.data.setdefault(DOMAIN, {})[entry.entry_id] = {
|
||||||
MONOPRICE_OBJECT: monoprice,
|
MONOPRICE_OBJECT: monoprice,
|
||||||
UNDO_UPDATE_LISTENER: undo_listener,
|
UNDO_UPDATE_LISTENER: undo_listener,
|
||||||
|
FIRST_RUN: first_run,
|
||||||
}
|
}
|
||||||
|
|
||||||
for component in PLATFORMS:
|
for component in PLATFORMS:
|
||||||
|
@ -11,8 +11,11 @@ CONF_SOURCE_4 = "source_4"
|
|||||||
CONF_SOURCE_5 = "source_5"
|
CONF_SOURCE_5 = "source_5"
|
||||||
CONF_SOURCE_6 = "source_6"
|
CONF_SOURCE_6 = "source_6"
|
||||||
|
|
||||||
|
CONF_NOT_FIRST_RUN = "not_first_run"
|
||||||
|
|
||||||
SERVICE_SNAPSHOT = "snapshot"
|
SERVICE_SNAPSHOT = "snapshot"
|
||||||
SERVICE_RESTORE = "restore"
|
SERVICE_RESTORE = "restore"
|
||||||
|
|
||||||
|
FIRST_RUN = "first_run"
|
||||||
MONOPRICE_OBJECT = "monoprice_object"
|
MONOPRICE_OBJECT = "monoprice_object"
|
||||||
UNDO_UPDATE_LISTENER = "update_update_listener"
|
UNDO_UPDATE_LISTENER = "update_update_listener"
|
||||||
|
@ -19,6 +19,7 @@ from homeassistant.helpers import config_validation as cv, entity_platform, serv
|
|||||||
from .const import (
|
from .const import (
|
||||||
CONF_SOURCES,
|
CONF_SOURCES,
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
|
FIRST_RUN,
|
||||||
MONOPRICE_OBJECT,
|
MONOPRICE_OBJECT,
|
||||||
SERVICE_RESTORE,
|
SERVICE_RESTORE,
|
||||||
SERVICE_SNAPSHOT,
|
SERVICE_SNAPSHOT,
|
||||||
@ -77,7 +78,9 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
|
|||||||
MonopriceZone(monoprice, sources, config_entry.entry_id, zone_id)
|
MonopriceZone(monoprice, sources, config_entry.entry_id, zone_id)
|
||||||
)
|
)
|
||||||
|
|
||||||
async_add_entities(entities, True)
|
# only call update before add if it's the first run so we can try to detect zones
|
||||||
|
first_run = hass.data[DOMAIN][config_entry.entry_id][FIRST_RUN]
|
||||||
|
async_add_entities(entities, first_run)
|
||||||
|
|
||||||
platform = entity_platform.current_platform.get()
|
platform = entity_platform.current_platform.get()
|
||||||
|
|
||||||
@ -134,16 +137,19 @@ class MonopriceZone(MediaPlayerEntity):
|
|||||||
self._volume = None
|
self._volume = None
|
||||||
self._source = None
|
self._source = None
|
||||||
self._mute = None
|
self._mute = None
|
||||||
|
self._update_success = True
|
||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
"""Retrieve latest state."""
|
"""Retrieve latest state."""
|
||||||
try:
|
try:
|
||||||
state = self._monoprice.zone_status(self._zone_id)
|
state = self._monoprice.zone_status(self._zone_id)
|
||||||
except SerialException:
|
except SerialException:
|
||||||
|
self._update_success = False
|
||||||
_LOGGER.warning("Could not update zone %d", self._zone_id)
|
_LOGGER.warning("Could not update zone %d", self._zone_id)
|
||||||
return
|
return
|
||||||
|
|
||||||
if not state:
|
if not state:
|
||||||
|
self._update_success = False
|
||||||
return
|
return
|
||||||
|
|
||||||
self._state = STATE_ON if state.power else STATE_OFF
|
self._state = STATE_ON if state.power else STATE_OFF
|
||||||
@ -158,7 +164,7 @@ class MonopriceZone(MediaPlayerEntity):
|
|||||||
@property
|
@property
|
||||||
def entity_registry_enabled_default(self):
|
def entity_registry_enabled_default(self):
|
||||||
"""Return if the entity should be enabled when first added to the entity registry."""
|
"""Return if the entity should be enabled when first added to the entity registry."""
|
||||||
return self._zone_id < 20
|
return self._zone_id < 20 or self._update_success
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def device_info(self):
|
def device_info(self):
|
||||||
|
@ -17,6 +17,7 @@ from homeassistant.components.media_player.const import (
|
|||||||
SUPPORT_VOLUME_STEP,
|
SUPPORT_VOLUME_STEP,
|
||||||
)
|
)
|
||||||
from homeassistant.components.monoprice.const import (
|
from homeassistant.components.monoprice.const import (
|
||||||
|
CONF_NOT_FIRST_RUN,
|
||||||
CONF_SOURCES,
|
CONF_SOURCES,
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
SERVICE_RESTORE,
|
SERVICE_RESTORE,
|
||||||
@ -41,6 +42,7 @@ MOCK_OPTIONS = {CONF_SOURCES: {"2": "two", "4": "four"}}
|
|||||||
|
|
||||||
ZONE_1_ID = "media_player.zone_11"
|
ZONE_1_ID = "media_player.zone_11"
|
||||||
ZONE_2_ID = "media_player.zone_12"
|
ZONE_2_ID = "media_player.zone_12"
|
||||||
|
ZONE_7_ID = "media_player.zone_21"
|
||||||
|
|
||||||
|
|
||||||
class AttrDict(dict):
|
class AttrDict(dict):
|
||||||
@ -100,8 +102,6 @@ async def test_cannot_connect(hass):
|
|||||||
config_entry = MockConfigEntry(domain=DOMAIN, data=MOCK_CONFIG)
|
config_entry = MockConfigEntry(domain=DOMAIN, data=MOCK_CONFIG)
|
||||||
config_entry.add_to_hass(hass)
|
config_entry.add_to_hass(hass)
|
||||||
await hass.config_entries.async_setup(config_entry.entry_id)
|
await hass.config_entries.async_setup(config_entry.entry_id)
|
||||||
# setup_component(self.hass, DOMAIN, MOCK_CONFIG)
|
|
||||||
# self.hass.async_block_till_done()
|
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
assert hass.states.get(ZONE_1_ID) is None
|
assert hass.states.get(ZONE_1_ID) is None
|
||||||
|
|
||||||
@ -113,8 +113,6 @@ async def _setup_monoprice(hass, monoprice):
|
|||||||
config_entry = MockConfigEntry(domain=DOMAIN, data=MOCK_CONFIG)
|
config_entry = MockConfigEntry(domain=DOMAIN, data=MOCK_CONFIG)
|
||||||
config_entry.add_to_hass(hass)
|
config_entry.add_to_hass(hass)
|
||||||
await hass.config_entries.async_setup(config_entry.entry_id)
|
await hass.config_entries.async_setup(config_entry.entry_id)
|
||||||
# setup_component(self.hass, DOMAIN, MOCK_CONFIG)
|
|
||||||
# self.hass.async_block_till_done()
|
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
|
||||||
@ -127,8 +125,17 @@ async def _setup_monoprice_with_options(hass, monoprice):
|
|||||||
)
|
)
|
||||||
config_entry.add_to_hass(hass)
|
config_entry.add_to_hass(hass)
|
||||||
await hass.config_entries.async_setup(config_entry.entry_id)
|
await hass.config_entries.async_setup(config_entry.entry_id)
|
||||||
# setup_component(self.hass, DOMAIN, MOCK_CONFIG)
|
await hass.async_block_till_done()
|
||||||
# self.hass.async_block_till_done()
|
|
||||||
|
|
||||||
|
async def _setup_monoprice_not_first_run(hass, monoprice):
|
||||||
|
with patch(
|
||||||
|
"homeassistant.components.monoprice.get_monoprice", new=lambda *a: monoprice,
|
||||||
|
):
|
||||||
|
data = {**MOCK_CONFIG, CONF_NOT_FIRST_RUN: True}
|
||||||
|
config_entry = MockConfigEntry(domain=DOMAIN, data=data)
|
||||||
|
config_entry.add_to_hass(hass)
|
||||||
|
await hass.config_entries.async_setup(config_entry.entry_id)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
|
||||||
@ -479,3 +486,47 @@ async def test_volume_up_down(hass):
|
|||||||
hass, SERVICE_VOLUME_DOWN, {"entity_id": ZONE_1_ID}
|
hass, SERVICE_VOLUME_DOWN, {"entity_id": ZONE_1_ID}
|
||||||
)
|
)
|
||||||
assert monoprice.zones[11].volume == 37
|
assert monoprice.zones[11].volume == 37
|
||||||
|
|
||||||
|
|
||||||
|
async def test_first_run_with_available_zones(hass):
|
||||||
|
"""Test first run with all zones available."""
|
||||||
|
monoprice = MockMonoprice()
|
||||||
|
await _setup_monoprice(hass, monoprice)
|
||||||
|
|
||||||
|
registry = await hass.helpers.entity_registry.async_get_registry()
|
||||||
|
|
||||||
|
entry = registry.async_get(ZONE_7_ID)
|
||||||
|
assert not entry.disabled
|
||||||
|
|
||||||
|
|
||||||
|
async def test_first_run_with_failing_zones(hass):
|
||||||
|
"""Test first run with failed zones."""
|
||||||
|
monoprice = MockMonoprice()
|
||||||
|
|
||||||
|
with patch.object(MockMonoprice, "zone_status", side_effect=SerialException):
|
||||||
|
await _setup_monoprice(hass, monoprice)
|
||||||
|
|
||||||
|
registry = await hass.helpers.entity_registry.async_get_registry()
|
||||||
|
|
||||||
|
entry = registry.async_get(ZONE_1_ID)
|
||||||
|
assert not entry.disabled
|
||||||
|
|
||||||
|
entry = registry.async_get(ZONE_7_ID)
|
||||||
|
assert entry.disabled
|
||||||
|
assert entry.disabled_by == "integration"
|
||||||
|
|
||||||
|
|
||||||
|
async def test_not_first_run_with_failing_zone(hass):
|
||||||
|
"""Test first run with failed zones."""
|
||||||
|
monoprice = MockMonoprice()
|
||||||
|
|
||||||
|
with patch.object(MockMonoprice, "zone_status", side_effect=SerialException):
|
||||||
|
await _setup_monoprice_not_first_run(hass, monoprice)
|
||||||
|
|
||||||
|
registry = await hass.helpers.entity_registry.async_get_registry()
|
||||||
|
|
||||||
|
entry = registry.async_get(ZONE_1_ID)
|
||||||
|
assert not entry.disabled
|
||||||
|
|
||||||
|
entry = registry.async_get(ZONE_7_ID)
|
||||||
|
assert not entry.disabled
|
||||||
|
Loading…
x
Reference in New Issue
Block a user