mirror of
https://github.com/home-assistant/core.git
synced 2025-07-11 07:17:12 +00:00
Squeezebox dispatch helper (#37030)
This commit is contained in:
parent
a798b508bc
commit
f7325a7d35
@ -1,55 +1,18 @@
|
|||||||
"""The Logitech Squeezebox integration."""
|
"""The Logitech Squeezebox integration."""
|
||||||
|
|
||||||
import asyncio
|
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from pysqueezebox import async_discover
|
|
||||||
|
|
||||||
from homeassistant.components.media_player import DOMAIN as MP_DOMAIN
|
from homeassistant.components.media_player import DOMAIN as MP_DOMAIN
|
||||||
from homeassistant.config_entries import SOURCE_DISCOVERY, ConfigEntry
|
from homeassistant.config_entries import ConfigEntry
|
||||||
from homeassistant.const import CONF_HOST, CONF_PORT, EVENT_HOMEASSISTANT_START
|
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
|
|
||||||
from .const import DOMAIN, ENTRY_PLAYERS, KNOWN_PLAYERS, PLAYER_DISCOVERY_UNSUB
|
from .const import DISCOVERY_TASK, DOMAIN, PLAYER_DISCOVERY_UNSUB
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
DISCOVERY_TASK = "discovery_task"
|
|
||||||
|
|
||||||
|
|
||||||
async def start_server_discovery(hass):
|
|
||||||
"""Start a server discovery task."""
|
|
||||||
|
|
||||||
def _discovered_server(server):
|
|
||||||
asyncio.create_task(
|
|
||||||
hass.config_entries.flow.async_init(
|
|
||||||
DOMAIN,
|
|
||||||
context={"source": SOURCE_DISCOVERY},
|
|
||||||
data={
|
|
||||||
CONF_HOST: server.host,
|
|
||||||
CONF_PORT: int(server.port),
|
|
||||||
"uuid": server.uuid,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
hass.data.setdefault(DOMAIN, {})
|
|
||||||
if DISCOVERY_TASK not in hass.data[DOMAIN]:
|
|
||||||
_LOGGER.debug("Adding server discovery task for squeezebox")
|
|
||||||
hass.data[DOMAIN][DISCOVERY_TASK] = hass.async_create_task(
|
|
||||||
async_discover(_discovered_server)
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
async def async_setup(hass: HomeAssistant, config: dict):
|
async def async_setup(hass: HomeAssistant, config: dict):
|
||||||
"""Set up the Logitech Squeezebox component."""
|
"""Set up the Logitech Squeezebox component."""
|
||||||
if hass.is_running:
|
|
||||||
asyncio.create_task(start_server_discovery(hass))
|
|
||||||
else:
|
|
||||||
hass.bus.async_listen_once(
|
|
||||||
EVENT_HOMEASSISTANT_START, start_server_discovery(hass)
|
|
||||||
)
|
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
@ -66,13 +29,6 @@ async def async_unload_entry(hass, entry):
|
|||||||
# Stop player discovery task for this config entry.
|
# Stop player discovery task for this config entry.
|
||||||
hass.data[DOMAIN][entry.entry_id][PLAYER_DISCOVERY_UNSUB]()
|
hass.data[DOMAIN][entry.entry_id][PLAYER_DISCOVERY_UNSUB]()
|
||||||
|
|
||||||
# Remove config entry's players from list of known players
|
|
||||||
entry_players = hass.data[DOMAIN][entry.entry_id][ENTRY_PLAYERS]
|
|
||||||
if entry_players:
|
|
||||||
for player in entry_players:
|
|
||||||
_LOGGER.debug("Remove entry player %s from list of known players.", player)
|
|
||||||
hass.data[DOMAIN][KNOWN_PLAYERS].remove(player)
|
|
||||||
|
|
||||||
# Remove stored data for this config entry
|
# Remove stored data for this config entry
|
||||||
hass.data[DOMAIN].pop(entry.entry_id)
|
hass.data[DOMAIN].pop(entry.entry_id)
|
||||||
|
|
||||||
|
@ -150,12 +150,11 @@ class SqueezeboxConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
|||||||
errors = {}
|
errors = {}
|
||||||
if user_input:
|
if user_input:
|
||||||
error = await self._validate_input(user_input)
|
error = await self._validate_input(user_input)
|
||||||
if error:
|
if not error:
|
||||||
errors["base"] = error
|
|
||||||
else:
|
|
||||||
return self.async_create_entry(
|
return self.async_create_entry(
|
||||||
title=user_input[CONF_HOST], data=user_input
|
title=user_input[CONF_HOST], data=user_input
|
||||||
)
|
)
|
||||||
|
errors["base"] = error
|
||||||
|
|
||||||
return self.async_show_form(
|
return self.async_show_form(
|
||||||
step_id="edit", data_schema=self.data_schema, errors=errors
|
step_id="edit", data_schema=self.data_schema, errors=errors
|
||||||
|
@ -3,4 +3,5 @@ DOMAIN = "squeezebox"
|
|||||||
ENTRY_PLAYERS = "entry_players"
|
ENTRY_PLAYERS = "entry_players"
|
||||||
KNOWN_PLAYERS = "known_players"
|
KNOWN_PLAYERS = "known_players"
|
||||||
PLAYER_DISCOVERY_UNSUB = "player_discovery_unsub"
|
PLAYER_DISCOVERY_UNSUB = "player_discovery_unsub"
|
||||||
|
DISCOVERY_TASK = "discovery_task"
|
||||||
DEFAULT_PORT = 9000
|
DEFAULT_PORT = 9000
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
import asyncio
|
import asyncio
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from pysqueezebox import Server
|
from pysqueezebox import Server, async_discover
|
||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
|
|
||||||
from homeassistant import config_entries
|
from homeassistant import config_entries
|
||||||
@ -23,6 +23,7 @@ from homeassistant.components.media_player.const import (
|
|||||||
SUPPORT_VOLUME_MUTE,
|
SUPPORT_VOLUME_MUTE,
|
||||||
SUPPORT_VOLUME_SET,
|
SUPPORT_VOLUME_SET,
|
||||||
)
|
)
|
||||||
|
from homeassistant.config_entries import SOURCE_DISCOVERY
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
ATTR_COMMAND,
|
ATTR_COMMAND,
|
||||||
CONF_HOST,
|
CONF_HOST,
|
||||||
@ -34,17 +35,20 @@ from homeassistant.const import (
|
|||||||
STATE_OFF,
|
STATE_OFF,
|
||||||
STATE_PAUSED,
|
STATE_PAUSED,
|
||||||
STATE_PLAYING,
|
STATE_PLAYING,
|
||||||
STATE_UNAVAILABLE,
|
|
||||||
)
|
)
|
||||||
|
from homeassistant.core import callback
|
||||||
from homeassistant.helpers import config_validation as cv, entity_platform
|
from homeassistant.helpers import config_validation as cv, entity_platform
|
||||||
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
||||||
|
from homeassistant.helpers.dispatcher import (
|
||||||
|
async_dispatcher_connect,
|
||||||
|
async_dispatcher_send,
|
||||||
|
)
|
||||||
from homeassistant.util.dt import utcnow
|
from homeassistant.util.dt import utcnow
|
||||||
|
|
||||||
from .__init__ import start_server_discovery
|
|
||||||
from .const import (
|
from .const import (
|
||||||
DEFAULT_PORT,
|
DEFAULT_PORT,
|
||||||
|
DISCOVERY_TASK,
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
ENTRY_PLAYERS,
|
|
||||||
KNOWN_PLAYERS,
|
KNOWN_PLAYERS,
|
||||||
PLAYER_DISCOVERY_UNSUB,
|
PLAYER_DISCOVERY_UNSUB,
|
||||||
)
|
)
|
||||||
@ -57,6 +61,8 @@ SERVICE_UNSYNC = "unsync"
|
|||||||
ATTR_QUERY_RESULT = "query_result"
|
ATTR_QUERY_RESULT = "query_result"
|
||||||
ATTR_SYNC_GROUP = "sync_group"
|
ATTR_SYNC_GROUP = "sync_group"
|
||||||
|
|
||||||
|
SIGNAL_PLAYER_REDISCOVERED = "squeezebox_player_rediscovered"
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
DISCOVERY_INTERVAL = 60
|
DISCOVERY_INTERVAL = 60
|
||||||
@ -107,6 +113,30 @@ SQUEEZEBOX_MODE = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async def start_server_discovery(hass):
|
||||||
|
"""Start a server discovery task."""
|
||||||
|
|
||||||
|
def _discovered_server(server):
|
||||||
|
asyncio.create_task(
|
||||||
|
hass.config_entries.flow.async_init(
|
||||||
|
DOMAIN,
|
||||||
|
context={"source": SOURCE_DISCOVERY},
|
||||||
|
data={
|
||||||
|
CONF_HOST: server.host,
|
||||||
|
CONF_PORT: int(server.port),
|
||||||
|
"uuid": server.uuid,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
hass.data.setdefault(DOMAIN, {})
|
||||||
|
if DISCOVERY_TASK not in hass.data[DOMAIN]:
|
||||||
|
_LOGGER.debug("Adding server discovery task for squeezebox")
|
||||||
|
hass.data[DOMAIN][DISCOVERY_TASK] = hass.async_create_task(
|
||||||
|
async_discover(_discovered_server)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
async def async_setup_platform(hass, config, async_add_entities, discovery_info=None):
|
async def async_setup_platform(hass, config, async_add_entities, discovery_info=None):
|
||||||
"""Set up squeezebox platform from platform entry in configuration.yaml (deprecated)."""
|
"""Set up squeezebox platform from platform entry in configuration.yaml (deprecated)."""
|
||||||
|
|
||||||
@ -129,13 +159,7 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
|
|||||||
hass.data.setdefault(DOMAIN, {})
|
hass.data.setdefault(DOMAIN, {})
|
||||||
hass.data[DOMAIN].setdefault(config_entry.entry_id, {})
|
hass.data[DOMAIN].setdefault(config_entry.entry_id, {})
|
||||||
|
|
||||||
known_players = hass.data[DOMAIN].get(KNOWN_PLAYERS)
|
known_players = hass.data[DOMAIN].setdefault(KNOWN_PLAYERS, [])
|
||||||
if known_players is None:
|
|
||||||
hass.data[DOMAIN][KNOWN_PLAYERS] = known_players = []
|
|
||||||
|
|
||||||
entry_players = hass.data[DOMAIN][config_entry.entry_id].setdefault(
|
|
||||||
ENTRY_PLAYERS, []
|
|
||||||
)
|
|
||||||
|
|
||||||
_LOGGER.debug("Creating LMS object for %s", host)
|
_LOGGER.debug("Creating LMS object for %s", host)
|
||||||
lms = Server(async_get_clientsession(hass), host, port, username, password)
|
lms = Server(async_get_clientsession(hass), host, port, username, password)
|
||||||
@ -153,15 +177,16 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
|
|||||||
),
|
),
|
||||||
None,
|
None,
|
||||||
)
|
)
|
||||||
if entity and not entity.available:
|
if entity:
|
||||||
# check if previously unavailable player has connected
|
|
||||||
await player.async_update()
|
await player.async_update()
|
||||||
entity.available = player.connected
|
async_dispatcher_send(
|
||||||
|
hass, SIGNAL_PLAYER_REDISCOVERED, player.player_id, player.connected
|
||||||
|
)
|
||||||
|
|
||||||
if not entity:
|
if not entity:
|
||||||
_LOGGER.debug("Adding new entity: %s", player)
|
_LOGGER.debug("Adding new entity: %s", player)
|
||||||
entity = SqueezeBoxEntity(player)
|
entity = SqueezeBoxEntity(player)
|
||||||
known_players.append(entity)
|
known_players.append(entity)
|
||||||
entry_players.append(entity)
|
|
||||||
async_add_entities([entity])
|
async_add_entities([entity])
|
||||||
|
|
||||||
players = await lms.async_get_players()
|
players = await lms.async_get_players()
|
||||||
@ -227,6 +252,7 @@ class SqueezeBoxEntity(MediaPlayerEntity):
|
|||||||
self._last_update = None
|
self._last_update = None
|
||||||
self._query_result = {}
|
self._query_result = {}
|
||||||
self._available = True
|
self._available = True
|
||||||
|
self._remove_dispatcher = None
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def device_state_attributes(self):
|
def device_state_attributes(self):
|
||||||
@ -254,16 +280,17 @@ class SqueezeBoxEntity(MediaPlayerEntity):
|
|||||||
"""Return True if device connected to LMS server."""
|
"""Return True if device connected to LMS server."""
|
||||||
return self._available
|
return self._available
|
||||||
|
|
||||||
@available.setter
|
@callback
|
||||||
def available(self, val):
|
def rediscovered(self, unique_id, connected):
|
||||||
"""Set available to True or False."""
|
"""Make a player available again."""
|
||||||
self._available = bool(val)
|
if unique_id == self.unique_id and connected:
|
||||||
|
self._available = True
|
||||||
|
_LOGGER.info("Player %s is available again", self.name)
|
||||||
|
self._remove_dispatcher()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def state(self):
|
def state(self):
|
||||||
"""Return the state of the device."""
|
"""Return the state of the device."""
|
||||||
if not self.available:
|
|
||||||
return STATE_UNAVAILABLE
|
|
||||||
if not self._player.power:
|
if not self._player.power:
|
||||||
return STATE_OFF
|
return STATE_OFF
|
||||||
if self._player.mode:
|
if self._player.mode:
|
||||||
@ -282,6 +309,15 @@ class SqueezeBoxEntity(MediaPlayerEntity):
|
|||||||
_LOGGER.info("Player %s is not available", self.name)
|
_LOGGER.info("Player %s is not available", self.name)
|
||||||
self._available = False
|
self._available = False
|
||||||
|
|
||||||
|
# start listening for restored players
|
||||||
|
self._remove_dispatcher = async_dispatcher_connect(
|
||||||
|
self.hass, SIGNAL_PLAYER_REDISCOVERED, self.rediscovered
|
||||||
|
)
|
||||||
|
|
||||||
|
async def async_will_remove_from_hass(self):
|
||||||
|
"""Remove from list of known players when removed from hass."""
|
||||||
|
self.hass.data[DOMAIN][KNOWN_PLAYERS].remove(self)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def volume_level(self):
|
def volume_level(self):
|
||||||
"""Volume level of the media player (0..1)."""
|
"""Volume level of the media player (0..1)."""
|
||||||
|
Loading…
x
Reference in New Issue
Block a user