Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Roon volume hooks #102470

Merged
merged 16 commits into from
Nov 12, 2023
1 change: 1 addition & 0 deletions .coveragerc
Original file line number Diff line number Diff line change
Expand Up @@ -1070,6 +1070,7 @@ omit =
homeassistant/components/roomba/sensor.py
homeassistant/components/roomba/vacuum.py
homeassistant/components/roon/__init__.py
homeassistant/components/roon/event.py
homeassistant/components/roon/media_browser.py
homeassistant/components/roon/media_player.py
homeassistant/components/roon/server.py
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/roon/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from .const import CONF_ROON_NAME, DOMAIN
from .server import RoonServer

PLATFORMS = [Platform.MEDIA_PLAYER]
PLATFORMS = [Platform.EVENT, Platform.MEDIA_PLAYER]


async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
Expand Down
7 changes: 5 additions & 2 deletions homeassistant/components/roon/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,12 @@

ROON_APPINFO = {
"extension_id": "home_assistant",
"display_name": "Roon Integration for Home Assistant",
"display_version": "1.0.0",
"display_name": "Home Assistant",
"display_version": "1.0.1",
"publisher": "home_assistant",
"email": "home_assistant@users.noreply.github.com",
"website": "https://www.home-assistant.io/",
}

ROON_EVENT_VOLUME_UP = "volume_up"
pavoni marked this conversation as resolved.
Show resolved Hide resolved
ROON_EVENT_VOLUME_DOWN = "volume_down"
104 changes: 104 additions & 0 deletions homeassistant/components/roon/event.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
"""Roon event entities."""
import logging
from typing import cast
pavoni marked this conversation as resolved.
Show resolved Hide resolved

from homeassistant.components.event import EventDeviceClass, EventEntity
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.device_registry import DeviceInfo
from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.helpers.entity_platform import AddEntitiesCallback

from .const import DOMAIN

_LOGGER = logging.getLogger(__name__)


async def async_setup_entry(
hass: HomeAssistant,
config_entry: ConfigEntry,
async_add_entities: AddEntitiesCallback,
) -> None:
"""Set up Roon Event from Config Entry."""
roon_server = hass.data[DOMAIN][config_entry.entry_id]
event_entities = set()

@callback
def async_add_roon_volume_entity(player_data):
"""Add or update Roon event Entity."""
dev_id = player_data["dev_id"]
if dev_id in event_entities:
return
# new player!
event_entity = RoonEventEntity(roon_server, player_data)
event_entities.add(dev_id)
async_add_entities([event_entity])

# start listening for players to be added from the server component
async_dispatcher_connect(hass, "roon_media_player", async_add_roon_volume_entity)
pavoni marked this conversation as resolved.
Show resolved Hide resolved


class RoonEventEntity(EventEntity):
"""Representation of a Roon Event entity."""

_attr_device_class = EventDeviceClass.BUTTON
MartinHjelmare marked this conversation as resolved.
Show resolved Hide resolved
_attr_event_types = ["volume_up", "volume_down"]
pavoni marked this conversation as resolved.
Show resolved Hide resolved

def __init__(self, server, player_data):
"""Initialize the entity."""
pavoni marked this conversation as resolved.
Show resolved Hide resolved
self._server = server
self._player_data = player_data
player_name = player_data["display_name"]
self._attr_name = f"{player_name} roon volume"
self._attr_unique_id = self._player_data["dev_id"]

if self._player_data.get("source_controls"):
dev_model = self._player_data["source_controls"][0].get("display_name")

self._attr_device_info = DeviceInfo(
identifiers={(DOMAIN, self.unique_id)},
# Instead of setting the device name to the entity name, roon
# should be updated to set has_entity_name = True, and set the entity
# name to None
name=cast(str | None, self.name),
manufacturer="RoonLabs",
model=dev_model,
via_device=(DOMAIN, self._server.roon_id),
)

@callback
def _roonapi_volume_callback(
self, control_key: str, event: str, value: int
) -> None:
"""Callbacks from the roon api with volume request."""

if event != "set_volume":
_LOGGER.debug("Received unsupported roon volume event %s", event)
return

if value > 0:
event = "volume_up"
else:
event = "volume_down"

self._trigger_event(event)
self.async_write_ha_state()

async def async_added_to_hass(self) -> None:
"""Register volume hooks with the roon api."""

self._server.roonapi.register_volume_control(
MartinHjelmare marked this conversation as resolved.
Show resolved Hide resolved
self.unique_id,
self.name,
self._roonapi_volume_callback,
0,
"incremental",
0,
0,
0,
False,
)

async def async_will_remove_from_hass(self) -> None:
"""Unregister volume hooks from the roon api."""
self._server.roonapi.unregister_volume_control(self.unique_id)
2 changes: 1 addition & 1 deletion homeassistant/components/roon/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@
"documentation": "https://www.home-assistant.io/integrations/roon",
"iot_class": "local_push",
"loggers": ["roonapi"],
"requirements": ["roonapi==0.1.4"]
"requirements": ["roonapi==0.1.5"]
}
2 changes: 1 addition & 1 deletion homeassistant/components/roon/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ def stop_roon(self):
self._exit = True

def roonapi_state_callback(self, event, changed_zones):
"""Callbacks from the roon api websockets."""
"""Callbacks from the roon api websocket with state change."""
self.hass.add_job(self.async_update_changed_players(changed_zones))

async def async_do_loop(self):
Expand Down
2 changes: 1 addition & 1 deletion requirements_all.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2344,7 +2344,7 @@ rokuecp==0.18.1
roombapy==1.6.8

# homeassistant.components.roon
roonapi==0.1.4
roonapi==0.1.5

# homeassistant.components.rova
rova==0.3.0
Expand Down
2 changes: 1 addition & 1 deletion requirements_test_all.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1743,7 +1743,7 @@ rokuecp==0.18.1
roombapy==1.6.8

# homeassistant.components.roon
roonapi==0.1.4
roonapi==0.1.5

# homeassistant.components.rpi_power
rpi-bad-power==0.1.0
Expand Down