Skip to content

Commit

Permalink
Update overlay documentation
Browse files Browse the repository at this point in the history
Update API to stop error messages
Simplify WebSocket listener startup process (Fixes 2.3.0 not receiving WebSocket events)
Remove broken support for .m3u playback, replace with error
  • Loading branch information
mj23000 committed Jun 24, 2024
1 parent c240457 commit d5ff56d
Show file tree
Hide file tree
Showing 15 changed files with 81 additions and 108 deletions.
84 changes: 45 additions & 39 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -161,44 +161,6 @@ The favourite buttons correspond to the physical favourite buttons on the device

### Automation examples

#### Using the overlay as doorbell

```yaml
description: Play doorbell sound overlay on doorbell press.
mode: single
trigger:
- platform: device
device_id: 1234567890abcdef1234567890abcdef
domain: example
type: doorbell
condition: []
action:
- service: bang_olufsen.overlay_audio
data:
uri: media-source://media_source/local/doorbell.mp3
absolute_volume: 60
target:
entity_id: media_player.beosound_balance_12345678
```
#### Using the overlay TTS as a bedtime reminder
```yaml
description: "Daily bedtime reminder using overlay TTS."
mode: single
trigger:
- platform: time
at: "22:00:00"
condition: []
action:
- service: bang_olufsen.overlay_audio
data:
absolute_volume: 70
tts: It is 22:00. Time to go to bed!
target:
entity_id: media_player.beosound_balance_12345678
```
#### Using the Beoremote One to control lights

```yaml
Expand Down Expand Up @@ -238,7 +200,7 @@ action:
### play_media services
The Bang & Olufsen integration supports different playback types in the `media_player.play_media` service: playback from URL, activating a favourite, playback from a local file, playing a radio station, activating a Deezer flow and Deezer playlists, albums and tracks.
The Bang & Olufsen integration supports different playback types in the `media_player.play_media` service: playback from URL, activating a favourite, playback from a local file, playing a radio station, activating a Deezer flow and Deezer/Tidal playlists, albums and tracks. Additionally `announce` can be set to `True` to play TTS or files as an overlay.

#### play_media examples

Expand Down Expand Up @@ -373,6 +335,50 @@ data:
media_content_type: radio
```

Playing a doorbell file with an absolute volume

```yaml
service: media_player.play_media
target:
entity_id: media_player.beosound_balance_12345678
data:
media_content_type: music
media_content_id: media-source://media_source/local/doorbell.mp3
announce: true
extra:
overlay_absolute_volume: 60
```

Playing an overlay TTS with an offset volume

TTS messages can be quiet, so an offset is useful in this scenario.

```yaml
service: media_player.play_media
target:
entity_id: media_player.beosound_balance_12345678
data:
media_content_type: overlay_tts
media_content_id: This is a test
announce: true
extra:
overlay_offset_volume: 10
```

Playing a Bang & Olufsen Cloud TTS message with a local language

```yaml
service: media_player.play_media
target:
entity_id: media_player.beosound_balance_12345678
data:
media_content_type: overlay_tts
media_content_id: Dette er en test
announce: true
extra:
overlay_tts_language: da-dk
```

_NOTE_: To easily obtain the media_content_id for a Deezer/Tidal track or B&O Radio station, you can enable the 'Media id' sensor on Mozart device in Home Assistant (disabled by default).
Once enabled, start playing the content you wish to activate in a service call - the Media id sensor will then provide the value to be used in the media_content_id field.

Expand Down
30 changes: 9 additions & 21 deletions custom_components/bang_olufsen/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
from homeassistant.const import CONF_HOST, CONF_MODEL, Platform
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ConfigEntryNotReady
from homeassistant.helpers import device_registry as dr, entity_registry as er
from homeassistant.helpers import device_registry as dr
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator

from .const import DOMAIN
Expand All @@ -24,7 +24,6 @@ class BangOlufsenData:

coordinator: DataUpdateCoordinator
client: MozartClient
entities_initialized: int = 0
platforms_initialized: int = 0


Expand All @@ -40,29 +39,18 @@ class BangOlufsenData:
]


async def _start_websocket_listener(
hass: HomeAssistant, entry: ConfigEntry, data: BangOlufsenData
) -> None:
"""Start WebSocket listener when all entities have been initialized."""
entity_registry = er.async_get(hass)
async def _start_websocket_listener(data: BangOlufsenData) -> None:
"""Start WebSocket listener when all platforms have been initialized."""

while True:
# Get all entries for entities and filter all disabled entities
entries = er.async_entries_for_config_entry(entity_registry, entry.entry_id)
expected_entities = len(
[entry for entry in entries if not entry.disabled or not entry.disabled_by]
)

# Check if all entities and platforms have been initialized and start WebSocket listener
if (
expected_entities == data.entities_initialized
and len(PLATFORMS) == data.platforms_initialized
):
await data.client.connect_notifications(remote_control=True, reconnect=True)
return
# Check if all platforms have been initialized and start WebSocket listener
if len(PLATFORMS) == data.platforms_initialized:
break

await asyncio.sleep(0)

await data.client.connect_notifications(remote_control=True, reconnect=True)


async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Set up from a config entry."""
Expand Down Expand Up @@ -102,7 +90,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
# Start WebSocket connection when all entities have been initialized
entry.async_create_background_task(
hass,
_start_websocket_listener(hass, entry, hass.data[DOMAIN][entry.entry_id]),
_start_websocket_listener(hass.data[DOMAIN][entry.entry_id]),
f"{DOMAIN}-{entry.unique_id}-websocket_starter",
)

Expand Down
4 changes: 0 additions & 4 deletions custom_components/bang_olufsen/binary_sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,6 @@ async def async_added_to_hass(self) -> None:
)
)

self.set_entity_initialized()

async def _update_battery_charging(self, data: BatteryState) -> None:
"""Update battery charging."""
self._attr_is_on = data.is_charging
Expand Down Expand Up @@ -130,8 +128,6 @@ async def async_added_to_hass(self) -> None:
)
)

self.set_entity_initialized()

async def _update_proximity(self, data: WebsocketNotificationTag) -> None:
"""Update proximity."""
if data.value:
Expand Down
2 changes: 0 additions & 2 deletions custom_components/bang_olufsen/button.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,6 @@ async def async_added_to_hass(self) -> None:

self._attr_extra_state_attributes = self._generate_favourite_attributes()

self.set_entity_initialized()

async def async_press(self) -> None:
"""Handle the action."""
await self._client.activate_preset(id=self._favourite_id)
Expand Down
4 changes: 0 additions & 4 deletions custom_components/bang_olufsen/entity.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,3 @@ def _async_update_connection_state(self, connection_state: bool) -> None:
self._attr_available = connection_state

self.async_write_ha_state()

def set_entity_initialized(self) -> None:
"""Increment number of initialized entities."""
self.hass.data[DOMAIN][self.entry.entry_id].entities_initialized += 1
20 changes: 10 additions & 10 deletions custom_components/bang_olufsen/icons.json
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
{
"services": {
"beolink_join": "mdi:location-enter",
"beolink_expand": "mdi:location-enter",
"beolink_unexpand": "mdi:location-exit",
"beolink_leave": "mdi:close-circle-outline",
"beolink_allstandby": "mdi:close-circle-multiple-outline",
"beolink_set_volume": "mdi:volume-equal",
"beolink_set_relative_volume": "mdi:volume-plus",
"beolink_leader_command": "mdi:location-enter"
}
"services": {
"beolink_join": "mdi:location-enter",
"beolink_expand": "mdi:location-enter",
"beolink_unexpand": "mdi:location-exit",
"beolink_leave": "mdi:close-circle-outline",
"beolink_allstandby": "mdi:close-circle-multiple-outline",
"beolink_set_volume": "mdi:volume-equal",
"beolink_set_relative_volume": "mdi:volume-plus",
"beolink_leader_command": "mdi:location-enter"
}
}
4 changes: 2 additions & 2 deletions custom_components/bang_olufsen/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"documentation": "https://github.com/bang-olufsen/bang_olufsen-hacs",
"iot_class": "local_push",
"issue_tracker": "https://github.com/bang-olufsen/bang_olufsen-hacs/issues",
"requirements": ["mozart-api==3.4.1.8.5"],
"version": "2.3.0",
"requirements": ["mozart-api==3.4.1.8.6"],
"version": "2.3.1",
"zeroconf": ["_bangolufsen._tcp.local."]
}
9 changes: 5 additions & 4 deletions custom_components/bang_olufsen/media_player.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@
SupportsResponse,
callback,
)
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers import (
config_validation as cv,
device_registry as dr,
Expand Down Expand Up @@ -391,8 +392,6 @@ async def async_added_to_hass(self) -> None:
)
)

self.set_entity_initialized()

async def _initialize(self) -> None:
"""Initialize connection dependent variables."""

Expand Down Expand Up @@ -1104,9 +1103,11 @@ async def async_play_media(

media_id = async_process_play_media_url(self.hass, sourced_media.url)

# Remove playlist extension as it is unsupported.
# Exit if the source uses unsupported file.
if media_id.endswith(".m3u"):
media_id = media_id.replace(".m3u", "")
raise HomeAssistantError(
translation_domain=DOMAIN, translation_key="m3u_invalid_format"
)

if announce:
extra = kwargs.get(ATTR_MEDIA_EXTRA, {})
Expand Down
4 changes: 0 additions & 4 deletions custom_components/bang_olufsen/number.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,6 @@ async def async_added_to_hass(self) -> None:
)
)

self.set_entity_initialized()

async def _update_sound_settings(self, data: SoundSettings) -> None:
"""Update sound settings."""
if data.adjustments and data.adjustments.treble:
Expand Down Expand Up @@ -133,8 +131,6 @@ async def async_added_to_hass(self) -> None:
)
)

self.set_entity_initialized()

async def _update_sound_settings(self, data: SoundSettings) -> None:
"""Update sound settings."""
if data.adjustments and data.adjustments.bass:
Expand Down
2 changes: 0 additions & 2 deletions custom_components/bang_olufsen/select.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,8 +101,6 @@ async def async_added_to_hass(self) -> None:

await self._update_listening_positions()

self.set_entity_initialized()

async def async_select_option(self, option: str) -> None:
"""Change the selected option."""
await self._client.post_scene_trigger(id=self._listening_positions[option])
Expand Down
10 changes: 0 additions & 10 deletions custom_components/bang_olufsen/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,8 +94,6 @@ async def async_added_to_hass(self) -> None:
)
)

self.set_entity_initialized()

async def _update_battery(self, data: BatteryState) -> None:
"""Update sensor value."""
self._attr_native_value = data.battery_level
Expand Down Expand Up @@ -134,8 +132,6 @@ async def async_added_to_hass(self) -> None:
)
)

self.set_entity_initialized()

async def _update_battery(self, data: BatteryState) -> None:
"""Update sensor value."""

Expand Down Expand Up @@ -184,8 +180,6 @@ async def async_added_to_hass(self) -> None:
)
)

self.set_entity_initialized()

async def _update_battery(self, data: BatteryState) -> None:
"""Update sensor value."""
self._attr_available = True
Expand Down Expand Up @@ -235,8 +229,6 @@ async def async_added_to_hass(self) -> None:
)
)

self.set_entity_initialized()

async def _update_playback_metadata(self, data: PlaybackContentMetadata) -> None:
"""Update Sensor value."""
self._attr_native_value = data.source_internal_id
Expand Down Expand Up @@ -275,8 +267,6 @@ async def async_added_to_hass(self) -> None:
)
)

self.set_entity_initialized()

async def _update_playback_metadata(self, data: PlaybackContentMetadata) -> None:
"""Update Sensor value."""
if data.encoding:
Expand Down
5 changes: 5 additions & 0 deletions custom_components/bang_olufsen/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -247,5 +247,10 @@
"friendly_name": { "name": "Device friendly name" },
"home_control_uri": { "name": "Home Control URI" }
}
},
"exceptions": {
"m3u_invalid_format": {
"message": "Media sources with the .m3u extension are not supported."
}
}
}
2 changes: 0 additions & 2 deletions custom_components/bang_olufsen/switch.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,6 @@ async def async_added_to_hass(self) -> None:
)
)

self.set_entity_initialized()

async def _update_sound_settings(self, data: SoundSettings) -> None:
"""Update sound settings."""
if data.adjustments and data.adjustments.loudness is not None:
Expand Down
4 changes: 0 additions & 4 deletions custom_components/bang_olufsen/text.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,6 @@ async def async_added_to_hass(self) -> None:
beolink_self = await self._client.get_beolink_self()
self._attr_native_value = beolink_self.friendly_name

self.set_entity_initialized()

async def async_set_value(self, value: str) -> None:
"""Set the friendly name."""
self._attr_native_value = value
Expand Down Expand Up @@ -129,8 +127,6 @@ async def async_added_to_hass(self) -> None:
home_control = await self._client.get_remote_home_control_uri()
self._attr_native_value = home_control.uri

self.set_entity_initialized()

async def async_set_value(self, value: str) -> None:
"""Set the Home Control URI name."""
self._attr_native_value = value
Expand Down
5 changes: 5 additions & 0 deletions custom_components/bang_olufsen/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,11 @@
}
}
},
"exceptions": {
"m3u_invalid_format": {
"message": "Media sources with the .m3u extension are not supported."
}
},
"services": {
"beolink_allstandby": {
"description": "Set all Connected Beolink devices to standby.",
Expand Down

0 comments on commit d5ff56d

Please sign in to comment.