mirror of
https://github.com/home-assistant/core.git
synced 2025-07-12 07:47:08 +00:00
Add Squeezebox server service binary sensors (#122473)
* squeezebox add binary sensor + coordinator * squeezebox add connected via for media_player * squeezebox add Player type for player * Add more type info * Fix linter errors * squeezebox use our own status entity * squeezebox rework device handling based on freedback * Fix device creation * squeezebox rework coordinator error handling * Fix lint type error * Correct spelling * Correct spelling * remove large comments * insert small comment * add translation support * Simply sensor * clean update function, minimise comments to the useful bits * Fix after testing * Update homeassistant/components/squeezebox/entity.py Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com> * move data prep out of Device assign for clarity * stop being a generic api * Humans need to read the sensors... * ruff format * Humans need to read the sensors... * Revert "ruff format" This reverts commit 8fcb8143e7c4427e75d31f9dd57f6c2027f8df6a. * ruff format * Humans need to read the sensors... * errors after testing * infered * drop context * cutdown coordinator for the binary sensors * add tests for binary sensors * Fix import * add some basic media_player tests * Fix spelling and file headers * Fix spelling * remove uuid and use service device cat * use diag device * assert execpted value * ruff format * Update homeassistant/components/squeezebox/__init__.py Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com> * Simplify T/F * Fix file header * remove redudant check * remove player tests from this commit * Fix formatting * remove unused * Fix function Type * Fix Any to bool * Fix browser tests * Patch our squeebox componemt not the server in the lib * ruff --------- Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
This commit is contained in:
parent
86ae70780c
commit
38f3fa0210
@ -1,6 +1,7 @@
|
|||||||
"""The Squeezebox integration."""
|
"""The Squeezebox integration."""
|
||||||
|
|
||||||
from asyncio import timeout
|
from asyncio import timeout
|
||||||
|
from dataclasses import dataclass
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from pysqueezebox import Server
|
from pysqueezebox import Server
|
||||||
@ -15,23 +16,42 @@ from homeassistant.const import (
|
|||||||
)
|
)
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.exceptions import ConfigEntryNotReady
|
from homeassistant.exceptions import ConfigEntryNotReady
|
||||||
|
from homeassistant.helpers import device_registry as dr
|
||||||
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
||||||
|
from homeassistant.helpers.device_registry import (
|
||||||
|
CONNECTION_NETWORK_MAC,
|
||||||
|
DeviceEntryType,
|
||||||
|
format_mac,
|
||||||
|
)
|
||||||
|
|
||||||
from .const import (
|
from .const import (
|
||||||
CONF_HTTPS,
|
CONF_HTTPS,
|
||||||
DISCOVERY_TASK,
|
DISCOVERY_TASK,
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
|
MANUFACTURER,
|
||||||
|
SERVER_MODEL,
|
||||||
STATUS_API_TIMEOUT,
|
STATUS_API_TIMEOUT,
|
||||||
STATUS_QUERY_LIBRARYNAME,
|
STATUS_QUERY_LIBRARYNAME,
|
||||||
|
STATUS_QUERY_MAC,
|
||||||
STATUS_QUERY_UUID,
|
STATUS_QUERY_UUID,
|
||||||
|
STATUS_QUERY_VERSION,
|
||||||
)
|
)
|
||||||
|
from .coordinator import LMSStatusDataUpdateCoordinator
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
PLATFORMS = [Platform.MEDIA_PLAYER]
|
PLATFORMS = [Platform.BINARY_SENSOR, Platform.MEDIA_PLAYER]
|
||||||
|
|
||||||
|
|
||||||
type SqueezeboxConfigEntry = ConfigEntry[Server]
|
@dataclass
|
||||||
|
class SqueezeboxData:
|
||||||
|
"""SqueezeboxData data class."""
|
||||||
|
|
||||||
|
coordinator: LMSStatusDataUpdateCoordinator
|
||||||
|
server: Server
|
||||||
|
|
||||||
|
|
||||||
|
type SqueezeboxConfigEntry = ConfigEntry[SqueezeboxData]
|
||||||
|
|
||||||
|
|
||||||
async def async_setup_entry(hass: HomeAssistant, entry: SqueezeboxConfigEntry) -> bool:
|
async def async_setup_entry(hass: HomeAssistant, entry: SqueezeboxConfigEntry) -> bool:
|
||||||
@ -66,25 +86,51 @@ async def async_setup_entry(hass: HomeAssistant, entry: SqueezeboxConfigEntry) -
|
|||||||
_LOGGER.debug("LMS Status for setup = %s", status)
|
_LOGGER.debug("LMS Status for setup = %s", status)
|
||||||
|
|
||||||
lms.uuid = status[STATUS_QUERY_UUID]
|
lms.uuid = status[STATUS_QUERY_UUID]
|
||||||
|
_LOGGER.debug("LMS %s = '%s' with uuid = %s ", lms.name, host, lms.uuid)
|
||||||
lms.name = (
|
lms.name = (
|
||||||
(STATUS_QUERY_LIBRARYNAME in status and status[STATUS_QUERY_LIBRARYNAME])
|
(STATUS_QUERY_LIBRARYNAME in status and status[STATUS_QUERY_LIBRARYNAME])
|
||||||
and status[STATUS_QUERY_LIBRARYNAME]
|
and status[STATUS_QUERY_LIBRARYNAME]
|
||||||
or host
|
or host
|
||||||
)
|
)
|
||||||
_LOGGER.debug("LMS %s = '%s' with uuid = %s ", lms.name, host, lms.uuid)
|
version = STATUS_QUERY_VERSION in status and status[STATUS_QUERY_VERSION] or None
|
||||||
|
# mac can be missing
|
||||||
|
mac_connect = (
|
||||||
|
{(CONNECTION_NETWORK_MAC, format_mac(status[STATUS_QUERY_MAC]))}
|
||||||
|
if STATUS_QUERY_MAC in status
|
||||||
|
else None
|
||||||
|
)
|
||||||
|
|
||||||
entry.runtime_data = lms
|
device_registry = dr.async_get(hass)
|
||||||
|
device = device_registry.async_get_or_create(
|
||||||
|
config_entry_id=entry.entry_id,
|
||||||
|
identifiers={(DOMAIN, lms.uuid)},
|
||||||
|
name=lms.name,
|
||||||
|
manufacturer=MANUFACTURER,
|
||||||
|
model=SERVER_MODEL,
|
||||||
|
sw_version=version,
|
||||||
|
entry_type=DeviceEntryType.SERVICE,
|
||||||
|
connections=mac_connect,
|
||||||
|
)
|
||||||
|
_LOGGER.debug("LMS Device %s", device)
|
||||||
|
|
||||||
|
coordinator = LMSStatusDataUpdateCoordinator(hass, lms)
|
||||||
|
|
||||||
|
entry.runtime_data = SqueezeboxData(
|
||||||
|
coordinator=coordinator,
|
||||||
|
server=lms,
|
||||||
|
)
|
||||||
|
|
||||||
|
await coordinator.async_config_entry_first_refresh()
|
||||||
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
|
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
async def async_unload_entry(hass: HomeAssistant, entry: SqueezeboxConfigEntry) -> bool:
|
||||||
"""Unload a config entry."""
|
"""Unload a config entry."""
|
||||||
# Stop player discovery task for this config entry.
|
# Stop player discovery task for this config entry.
|
||||||
_LOGGER.debug(
|
_LOGGER.debug(
|
||||||
"Reached async_unload_entry for LMS=%s(%s)",
|
"Reached async_unload_entry for LMS=%s(%s)",
|
||||||
entry.runtime_data.name or "Unknown",
|
entry.runtime_data.server.name or "Unknown",
|
||||||
entry.entry_id,
|
entry.entry_id,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
54
homeassistant/components/squeezebox/binary_sensor.py
Normal file
54
homeassistant/components/squeezebox/binary_sensor.py
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
"""Binary sensor platform for Squeezebox integration."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from homeassistant.components.binary_sensor import (
|
||||||
|
BinarySensorDeviceClass,
|
||||||
|
BinarySensorEntity,
|
||||||
|
BinarySensorEntityDescription,
|
||||||
|
)
|
||||||
|
from homeassistant.const import EntityCategory
|
||||||
|
from homeassistant.core import HomeAssistant
|
||||||
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
|
|
||||||
|
from . import SqueezeboxConfigEntry
|
||||||
|
from .const import STATUS_SENSOR_NEEDSRESTART, STATUS_SENSOR_RESCAN
|
||||||
|
from .entity import LMSStatusEntity
|
||||||
|
|
||||||
|
SENSORS: tuple[BinarySensorEntityDescription, ...] = (
|
||||||
|
BinarySensorEntityDescription(
|
||||||
|
key=STATUS_SENSOR_RESCAN,
|
||||||
|
device_class=BinarySensorDeviceClass.RUNNING,
|
||||||
|
),
|
||||||
|
BinarySensorEntityDescription(
|
||||||
|
key=STATUS_SENSOR_NEEDSRESTART,
|
||||||
|
device_class=BinarySensorDeviceClass.UPDATE,
|
||||||
|
entity_category=EntityCategory.DIAGNOSTIC,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
async def async_setup_entry(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
entry: SqueezeboxConfigEntry,
|
||||||
|
async_add_entities: AddEntitiesCallback,
|
||||||
|
) -> None:
|
||||||
|
"""Platform setup using common elements."""
|
||||||
|
|
||||||
|
async_add_entities(
|
||||||
|
ServerStatusBinarySensor(entry.runtime_data.coordinator, description)
|
||||||
|
for description in SENSORS
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class ServerStatusBinarySensor(LMSStatusEntity, BinarySensorEntity):
|
||||||
|
"""LMS Status based sensor from LMS via cooridnatior."""
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_on(self) -> bool:
|
||||||
|
"""LMS Status directly from coordinator data."""
|
||||||
|
return bool(self.coordinator.data[self.entity_description.key])
|
@ -5,8 +5,25 @@ DISCOVERY_TASK = "discovery_task"
|
|||||||
DOMAIN = "squeezebox"
|
DOMAIN = "squeezebox"
|
||||||
DEFAULT_PORT = 9000
|
DEFAULT_PORT = 9000
|
||||||
KNOWN_PLAYERS = "known_players"
|
KNOWN_PLAYERS = "known_players"
|
||||||
|
MANUFACTURER = "https://lyrion.org/"
|
||||||
|
PLAYER_DISCOVERY_UNSUB = "player_discovery_unsub"
|
||||||
SENSOR_UPDATE_INTERVAL = 60
|
SENSOR_UPDATE_INTERVAL = 60
|
||||||
|
SERVER_MODEL = "Lyron Music Server"
|
||||||
STATUS_API_TIMEOUT = 10
|
STATUS_API_TIMEOUT = 10
|
||||||
|
STATUS_SENSOR_LASTSCAN = "lastscan"
|
||||||
|
STATUS_SENSOR_NEEDSRESTART = "needsrestart"
|
||||||
|
STATUS_SENSOR_NEWVERSION = "newversion"
|
||||||
|
STATUS_SENSOR_NEWPLUGINS = "newplugins"
|
||||||
|
STATUS_SENSOR_RESCAN = "rescan"
|
||||||
|
STATUS_SENSOR_INFO_TOTAL_ALBUMS = "info total albums"
|
||||||
|
STATUS_SENSOR_INFO_TOTAL_ARTISTS = "info total artists"
|
||||||
|
STATUS_SENSOR_INFO_TOTAL_DURATION = "info total duration"
|
||||||
|
STATUS_SENSOR_INFO_TOTAL_GENRES = "info total genres"
|
||||||
|
STATUS_SENSOR_INFO_TOTAL_SONGS = "info total songs"
|
||||||
|
STATUS_SENSOR_PLAYER_COUNT = "player count"
|
||||||
|
STATUS_SENSOR_OTHER_PLAYER_COUNT = "other player count"
|
||||||
STATUS_QUERY_LIBRARYNAME = "libraryname"
|
STATUS_QUERY_LIBRARYNAME = "libraryname"
|
||||||
|
STATUS_QUERY_MAC = "mac"
|
||||||
STATUS_QUERY_UUID = "uuid"
|
STATUS_QUERY_UUID = "uuid"
|
||||||
|
STATUS_QUERY_VERSION = "version"
|
||||||
SQUEEZEBOX_SOURCE_STRINGS = ("source:", "wavin:", "spotify:")
|
SQUEEZEBOX_SOURCE_STRINGS = ("source:", "wavin:", "spotify:")
|
||||||
|
59
homeassistant/components/squeezebox/coordinator.py
Normal file
59
homeassistant/components/squeezebox/coordinator.py
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
"""DataUpdateCoordinator for the Squeezebox integration."""
|
||||||
|
|
||||||
|
from asyncio import timeout
|
||||||
|
from datetime import timedelta
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from pysqueezebox import Server
|
||||||
|
|
||||||
|
from homeassistant.core import HomeAssistant
|
||||||
|
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
|
||||||
|
|
||||||
|
from .const import (
|
||||||
|
SENSOR_UPDATE_INTERVAL,
|
||||||
|
STATUS_API_TIMEOUT,
|
||||||
|
STATUS_SENSOR_NEEDSRESTART,
|
||||||
|
STATUS_SENSOR_RESCAN,
|
||||||
|
)
|
||||||
|
|
||||||
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class LMSStatusDataUpdateCoordinator(DataUpdateCoordinator):
|
||||||
|
"""LMS Status custom coordinator."""
|
||||||
|
|
||||||
|
def __init__(self, hass: HomeAssistant, lms: Server) -> None:
|
||||||
|
"""Initialize my coordinator."""
|
||||||
|
super().__init__(
|
||||||
|
hass,
|
||||||
|
_LOGGER,
|
||||||
|
name=lms.name,
|
||||||
|
update_interval=timedelta(seconds=SENSOR_UPDATE_INTERVAL),
|
||||||
|
always_update=False,
|
||||||
|
)
|
||||||
|
self.lms = lms
|
||||||
|
|
||||||
|
async def _async_update_data(self) -> dict:
|
||||||
|
"""Fetch data fromn LMS status call.
|
||||||
|
|
||||||
|
Then we process only a subset to make then nice for HA
|
||||||
|
"""
|
||||||
|
async with timeout(STATUS_API_TIMEOUT):
|
||||||
|
data = await self.lms.async_status()
|
||||||
|
|
||||||
|
if not data:
|
||||||
|
raise UpdateFailed("No data from status poll")
|
||||||
|
_LOGGER.debug("Raw serverstatus %s=%s", self.lms.name, data)
|
||||||
|
|
||||||
|
return self._prepare_status_data(data)
|
||||||
|
|
||||||
|
def _prepare_status_data(self, data: dict) -> dict:
|
||||||
|
"""Sensors that need the data changing for HA presentation."""
|
||||||
|
|
||||||
|
# rescan bool are we rescanning alter poll not present if false
|
||||||
|
data[STATUS_SENSOR_RESCAN] = STATUS_SENSOR_RESCAN in data
|
||||||
|
# needsrestart bool pending lms plugin updates not present if false
|
||||||
|
data[STATUS_SENSOR_NEEDSRESTART] = STATUS_SENSOR_NEEDSRESTART in data
|
||||||
|
|
||||||
|
_LOGGER.debug("Processed serverstatus %s=%s", self.lms.name, data)
|
||||||
|
return data
|
31
homeassistant/components/squeezebox/entity.py
Normal file
31
homeassistant/components/squeezebox/entity.py
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
"""Base class for Squeezebox Sensor entities."""
|
||||||
|
|
||||||
|
from homeassistant.helpers.device_registry import DeviceInfo
|
||||||
|
from homeassistant.helpers.entity import EntityDescription
|
||||||
|
from homeassistant.helpers.update_coordinator import CoordinatorEntity
|
||||||
|
|
||||||
|
from .const import DOMAIN, STATUS_QUERY_UUID
|
||||||
|
from .coordinator import LMSStatusDataUpdateCoordinator
|
||||||
|
|
||||||
|
|
||||||
|
class LMSStatusEntity(CoordinatorEntity[LMSStatusDataUpdateCoordinator]):
|
||||||
|
"""Defines a base status sensor entity."""
|
||||||
|
|
||||||
|
_attr_has_entity_name = True
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
coordinator: LMSStatusDataUpdateCoordinator,
|
||||||
|
description: EntityDescription,
|
||||||
|
) -> None:
|
||||||
|
"""Initialize status sensor entity."""
|
||||||
|
super().__init__(coordinator)
|
||||||
|
self.entity_description = description
|
||||||
|
self._attr_translation_key = description.key
|
||||||
|
self._attr_unique_id = (
|
||||||
|
f"{coordinator.data[STATUS_QUERY_UUID]}_{description.key}"
|
||||||
|
)
|
||||||
|
|
||||||
|
self._attr_device_info = DeviceInfo(
|
||||||
|
identifiers={(DOMAIN, coordinator.data[STATUS_QUERY_UUID])},
|
||||||
|
)
|
@ -113,7 +113,7 @@ async def async_setup_entry(
|
|||||||
"""Set up an player discovery from a config entry."""
|
"""Set up an player discovery from a config entry."""
|
||||||
hass.data.setdefault(DOMAIN, {})
|
hass.data.setdefault(DOMAIN, {})
|
||||||
known_players = hass.data[DOMAIN].setdefault(KNOWN_PLAYERS, [])
|
known_players = hass.data[DOMAIN].setdefault(KNOWN_PLAYERS, [])
|
||||||
lms = entry.runtime_data
|
lms = entry.runtime_data.server
|
||||||
|
|
||||||
async def _player_discovery(now: datetime | None = None) -> None:
|
async def _player_discovery(now: datetime | None = None) -> None:
|
||||||
"""Discover squeezebox players by polling server."""
|
"""Discover squeezebox players by polling server."""
|
||||||
@ -136,7 +136,7 @@ async def async_setup_entry(
|
|||||||
|
|
||||||
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, lms)
|
||||||
known_players.append(entity)
|
known_players.append(entity)
|
||||||
async_add_entities([entity])
|
async_add_entities([entity])
|
||||||
|
|
||||||
@ -212,7 +212,7 @@ class SqueezeBoxEntity(MediaPlayerEntity):
|
|||||||
_last_update: datetime | None = None
|
_last_update: datetime | None = None
|
||||||
_attr_available = True
|
_attr_available = True
|
||||||
|
|
||||||
def __init__(self, player: Player) -> None:
|
def __init__(self, player: Player, server: Server) -> None:
|
||||||
"""Initialize the SqueezeBox device."""
|
"""Initialize the SqueezeBox device."""
|
||||||
self._player = player
|
self._player = player
|
||||||
self._query_result: bool | dict = {}
|
self._query_result: bool | dict = {}
|
||||||
@ -222,6 +222,7 @@ class SqueezeBoxEntity(MediaPlayerEntity):
|
|||||||
identifiers={(DOMAIN, self._attr_unique_id)},
|
identifiers={(DOMAIN, self._attr_unique_id)},
|
||||||
name=player.name,
|
name=player.name,
|
||||||
connections={(CONNECTION_NETWORK_MAC, self._attr_unique_id)},
|
connections={(CONNECTION_NETWORK_MAC, self._attr_unique_id)},
|
||||||
|
via_device=(DOMAIN, server.uuid),
|
||||||
)
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
@ -75,5 +75,15 @@
|
|||||||
"name": "Unsync",
|
"name": "Unsync",
|
||||||
"description": "Removes this player from its sync group."
|
"description": "Removes this player from its sync group."
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"entity": {
|
||||||
|
"binary_sensor": {
|
||||||
|
"rescan": {
|
||||||
|
"name": "Library rescan"
|
||||||
|
},
|
||||||
|
"needsrestart": {
|
||||||
|
"name": "Needs restart"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1 +1,69 @@
|
|||||||
"""Tests for the Logitech Squeezebox integration."""
|
"""Tests for the Logitech Squeezebox integration."""
|
||||||
|
|
||||||
|
from homeassistant.components.squeezebox.const import (
|
||||||
|
DOMAIN,
|
||||||
|
STATUS_QUERY_LIBRARYNAME,
|
||||||
|
STATUS_QUERY_MAC,
|
||||||
|
STATUS_QUERY_UUID,
|
||||||
|
STATUS_QUERY_VERSION,
|
||||||
|
STATUS_SENSOR_RESCAN,
|
||||||
|
)
|
||||||
|
from homeassistant.const import CONF_HOST, CONF_PORT
|
||||||
|
from homeassistant.core import HomeAssistant
|
||||||
|
|
||||||
|
# from homeassistant.setup import async_setup_component
|
||||||
|
from tests.common import MockConfigEntry
|
||||||
|
|
||||||
|
FAKE_IP = "42.42.42.42"
|
||||||
|
FAKE_MAC = "deadbeefdead"
|
||||||
|
FAKE_UUID = "deadbeefdeadbeefbeefdeafbeef42"
|
||||||
|
FAKE_PORT = 9000
|
||||||
|
FAKE_VERSION = "42.0"
|
||||||
|
|
||||||
|
FAKE_QUERY_RESPONSE = {
|
||||||
|
STATUS_QUERY_UUID: FAKE_UUID,
|
||||||
|
STATUS_QUERY_MAC: FAKE_MAC,
|
||||||
|
STATUS_QUERY_VERSION: FAKE_VERSION,
|
||||||
|
STATUS_SENSOR_RESCAN: 1,
|
||||||
|
STATUS_QUERY_LIBRARYNAME: "FakeLib",
|
||||||
|
"players_loop": [
|
||||||
|
{
|
||||||
|
"isplaying": 0,
|
||||||
|
"name": "SqueezeLite-HA-Addon",
|
||||||
|
"seq_no": 0,
|
||||||
|
"modelname": "SqueezeLite-HA-Addon",
|
||||||
|
"playerindex": "status",
|
||||||
|
"model": "squeezelite",
|
||||||
|
"uuid": FAKE_UUID,
|
||||||
|
"canpoweroff": 1,
|
||||||
|
"ip": "192.168.78.86:57700",
|
||||||
|
"displaytype": "none",
|
||||||
|
"playerid": "f9:23:cd:37:c5:ff",
|
||||||
|
"power": 0,
|
||||||
|
"isplayer": 1,
|
||||||
|
"connected": 1,
|
||||||
|
"firmware": "v2.0.0-1488",
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"count": 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async def setup_mocked_integration(hass: HomeAssistant) -> MockConfigEntry:
|
||||||
|
"""Mock ConfigEntry in Home Assistant."""
|
||||||
|
|
||||||
|
entry = MockConfigEntry(
|
||||||
|
domain=DOMAIN,
|
||||||
|
unique_id=FAKE_UUID,
|
||||||
|
data={
|
||||||
|
CONF_HOST: FAKE_IP,
|
||||||
|
CONF_PORT: FAKE_PORT,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
entry.add_to_hass(hass)
|
||||||
|
|
||||||
|
await hass.config_entries.async_setup(entry.entry_id)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
return entry
|
||||||
|
@ -130,4 +130,5 @@ def lms() -> MagicMock:
|
|||||||
)
|
)
|
||||||
lms.async_get_players = AsyncMock(return_value=[player])
|
lms.async_get_players = AsyncMock(return_value=[player])
|
||||||
lms.async_query = AsyncMock(return_value={"uuid": format_mac(TEST_MAC)})
|
lms.async_query = AsyncMock(return_value={"uuid": format_mac(TEST_MAC)})
|
||||||
|
lms.async_status = AsyncMock(return_value={"uuid": format_mac(TEST_MAC)})
|
||||||
return lms
|
return lms
|
||||||
|
33
tests/components/squeezebox/test_binary_sensor.py
Normal file
33
tests/components/squeezebox/test_binary_sensor.py
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
"""Test squeezebox binary sensors."""
|
||||||
|
|
||||||
|
from unittest.mock import patch
|
||||||
|
|
||||||
|
from homeassistant.const import Platform
|
||||||
|
from homeassistant.core import HomeAssistant
|
||||||
|
from homeassistant.helpers import entity_registry as er
|
||||||
|
|
||||||
|
from . import FAKE_QUERY_RESPONSE, setup_mocked_integration
|
||||||
|
|
||||||
|
|
||||||
|
async def test_binary_sensor(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
entity_registry: er.EntityRegistry,
|
||||||
|
) -> None:
|
||||||
|
"""Test binary sensor states and attributes."""
|
||||||
|
|
||||||
|
# Setup component
|
||||||
|
with (
|
||||||
|
patch(
|
||||||
|
"homeassistant.components.squeezebox.PLATFORMS",
|
||||||
|
[Platform.BINARY_SENSOR],
|
||||||
|
),
|
||||||
|
patch(
|
||||||
|
"homeassistant.components.squeezebox.Server.async_query",
|
||||||
|
return_value=FAKE_QUERY_RESPONSE,
|
||||||
|
),
|
||||||
|
):
|
||||||
|
await setup_mocked_integration(hass)
|
||||||
|
state = hass.states.get("binary_sensor.fakelib_library_rescan")
|
||||||
|
|
||||||
|
assert state is not None
|
||||||
|
assert state.state == "on"
|
@ -16,7 +16,7 @@ from homeassistant.components.squeezebox.browse_media import (
|
|||||||
LIBRARY,
|
LIBRARY,
|
||||||
MEDIA_TYPE_TO_SQUEEZEBOX,
|
MEDIA_TYPE_TO_SQUEEZEBOX,
|
||||||
)
|
)
|
||||||
from homeassistant.const import ATTR_ENTITY_ID
|
from homeassistant.const import ATTR_ENTITY_ID, Platform
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
|
|
||||||
from tests.common import MockConfigEntry
|
from tests.common import MockConfigEntry
|
||||||
@ -30,6 +30,10 @@ async def setup_integration(
|
|||||||
"""Fixture for setting up the component."""
|
"""Fixture for setting up the component."""
|
||||||
with (
|
with (
|
||||||
patch("homeassistant.components.squeezebox.Server", return_value=lms),
|
patch("homeassistant.components.squeezebox.Server", return_value=lms),
|
||||||
|
patch(
|
||||||
|
"homeassistant.components.squeezebox.PLATFORMS",
|
||||||
|
[Platform.MEDIA_PLAYER],
|
||||||
|
),
|
||||||
patch(
|
patch(
|
||||||
"homeassistant.components.squeezebox.media_player.start_server_discovery"
|
"homeassistant.components.squeezebox.media_player.start_server_discovery"
|
||||||
),
|
),
|
||||||
|
Loading…
x
Reference in New Issue
Block a user