1 """The Squeezebox integration."""
3 from asyncio
import timeout
4 from dataclasses
import dataclass
5 from datetime
import datetime
8 from pysqueezebox
import Player, Server
23 CONNECTION_NETWORK_MAC,
39 SIGNAL_PLAYER_DISCOVERED,
40 SIGNAL_PLAYER_REDISCOVERED,
42 STATUS_QUERY_LIBRARYNAME,
47 from .coordinator
import (
48 LMSStatusDataUpdateCoordinator,
49 SqueezeBoxPlayerUpdateCoordinator,
52 _LOGGER = logging.getLogger(__name__)
55 Platform.BINARY_SENSOR,
56 Platform.MEDIA_PLAYER,
63 """SqueezeboxData data class."""
65 coordinator: LMSStatusDataUpdateCoordinator
69 type SqueezeboxConfigEntry = ConfigEntry[SqueezeboxData]
73 """Set up an LMS Server from a config entry."""
77 "Reached async_setup_entry for host=%s(%s)", config[CONF_HOST], entry.entry_id
80 username = config.get(CONF_USERNAME)
81 password = config.get(CONF_PASSWORD)
82 https = config.get(CONF_HTTPS,
False)
83 host = config[CONF_HOST]
84 port = config[CONF_PORT]
86 lms = Server(session, host, port, username, password, https=https)
87 _LOGGER.debug(
"LMS object for %s", lms)
90 async
with timeout(STATUS_API_TIMEOUT):
91 status = await lms.async_query(
92 "serverstatus",
"-",
"-",
"prefs:libraryname"
94 except Exception
as err:
96 f
"Error communicating config not read for {host}"
101 _LOGGER.debug(
"LMS Status for setup = %s", status)
103 lms.uuid = status[STATUS_QUERY_UUID]
104 _LOGGER.debug(
"LMS %s = '%s' with uuid = %s ", lms.name, host, lms.uuid)
106 (STATUS_QUERY_LIBRARYNAME
in status
and status[STATUS_QUERY_LIBRARYNAME])
107 and status[STATUS_QUERY_LIBRARYNAME]
110 version = STATUS_QUERY_VERSION
in status
and status[STATUS_QUERY_VERSION]
or None
113 {(CONNECTION_NETWORK_MAC,
format_mac(status[STATUS_QUERY_MAC]))}
114 if STATUS_QUERY_MAC
in status
118 device_registry = dr.async_get(hass)
119 device = device_registry.async_get_or_create(
120 config_entry_id=entry.entry_id,
121 identifiers={(DOMAIN, lms.uuid)},
123 manufacturer=MANUFACTURER,
126 entry_type=DeviceEntryType.SERVICE,
127 connections=mac_connect,
129 _LOGGER.debug(
"LMS Device %s", device)
134 coordinator=server_coordinator,
139 known_servers = hass.data.setdefault(DOMAIN, {}).setdefault(KNOWN_SERVERS, {})
140 known_players = known_servers.setdefault(lms.uuid, {}).setdefault(KNOWN_PLAYERS, [])
142 async
def _player_discovery(now: datetime |
None =
None) ->
None:
143 """Discover squeezebox players by polling server."""
145 async
def _discovered_player(player: Player) ->
None:
146 """Handle a (re)discovered player."""
147 if player.player_id
in known_players:
148 await player.async_update()
150 hass, SIGNAL_PLAYER_REDISCOVERED, player.player_id, player.connected
153 _LOGGER.debug(
"Adding new entity: %s", player)
155 hass, player, lms.uuid
157 known_players.append(player.player_id)
159 hass, SIGNAL_PLAYER_DISCOVERED, player_coordinator
162 if players := await lms.async_get_players():
163 for player
in players:
164 hass.async_create_task(_discovered_player(player))
166 entry.async_on_unload(
170 await server_coordinator.async_config_entry_first_refresh()
171 await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
174 "Adding player discovery job for LMS server: %s", entry.data[CONF_HOST]
176 entry.async_create_background_task(
177 hass, _player_discovery(),
"squeezebox.media_player.player_discovery"
184 """Unload a config entry."""
187 "Reached async_unload_entry for LMS=%s(%s)",
188 entry.runtime_data.server.name
or "Unknown",
193 current_entries = hass.config_entries.async_entries(DOMAIN)
194 if len(current_entries) == 1
and current_entries[0] == entry:
195 _LOGGER.debug(
"Stopping server discovery task")
196 hass.data[DOMAIN][DISCOVERY_TASK].cancel()
197 hass.data[DOMAIN].pop(DISCOVERY_TASK)
199 return await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
bool async_setup_entry(HomeAssistant hass, SqueezeboxConfigEntry entry)
bool async_unload_entry(HomeAssistant hass, SqueezeboxConfigEntry entry)
aiohttp.ClientSession async_get_clientsession(HomeAssistant hass, bool verify_ssl=True, socket.AddressFamily family=socket.AF_UNSPEC, ssl_util.SSLCipherList ssl_cipher=ssl_util.SSLCipherList.PYTHON_DEFAULT)
None async_dispatcher_send(HomeAssistant hass, str signal, *Any args)
CALLBACK_TYPE async_call_later(HomeAssistant hass, float|timedelta delay, HassJob[[datetime], Coroutine[Any, Any, None]|None]|Callable[[datetime], Coroutine[Any, Any, None]|None] action)