Skip to content

Commit

Permalink
Add Christian Klits video and blueprints to README
Browse files Browse the repository at this point in the history
Remove old automation examples and Blueprints
Add better source checking, ensuring that all sources that are shown are available
Add sections to custom services that use JIDs
  • Loading branch information
mj23000 committed Nov 6, 2024
1 parent 41332cc commit bfaa310
Show file tree
Hide file tree
Showing 8 changed files with 138 additions and 152 deletions.
111 changes: 18 additions & 93 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,24 @@ This integration can be added to a Home Assistant installation using [HACS](http

Afterwards, devices can be added to your Home Assistant installation manually by using the UI or by auto-discovery.

## Example setup and blueprints

Christian Klit has made a setup video for Home Assistant which includes this integration.
[![Setup video](https://img.youtube.com/vi/ju_gQDIme0w/0.jpg)](https://www.youtube.com/watch?v=ju_gQDIme0w)

As can be seen in the video, Christian also provides several [automation blueprints](https://cklit.dk/index.php/category/blueprints/mozart/) for this integration on his website.

These include:

- Control lights using Beoremote One
- Control shades using Beoremote One
- Announce where music has been joined from (Beolink)
- Control scenes using Light and Control menu items on BR1 BT
- Trigger a scene, when alarm starts
- Show active Listening position and Sound mode on LG screen

Go to his website [cklit.dk](https://cklit.dk/) to see more information on the useful blueprints for the Mozart and ASE based Bang & Olufsen products.

## Entities

This integration adds an array of different useful entities that are generated and added automatically upon setup, customized for the supported features of the device. Some of these features, such as `proximity sensor` and `home-control` are manually defined based on model name in the code, as they currently can't be determined in any other way.
Expand Down Expand Up @@ -182,43 +200,6 @@ Event entities are available for each of the compatible keys on the [Beoremote O

The favourite buttons correspond to the physical favourite buttons on the device.

### Automation examples

#### Using the Beoremote One to control lights (OUTDATED)

```yaml
description: Use the Beoremote One to control living room lights.
mode: single
trigger:
- platform: device
device_id: 234567890abcdef1234567890abcdef1
domain: bang_olufsen
type: Light/Digit1_KeyPress
condition: []
action:
- service: light.toggle
target:
entity_id: light.living_room
```
#### Setting all devices to standby when leaving home (OUTDATED)
```yaml
description: Set all Bang & Olufsen devices to standby when leaving home.
mode: single
trigger:
- platform: zone
entity_id: person.example
zone: zone.home
event: leave
condition: []
action:
- service: bang_olufsen.beolink_allstandby
data: {}
target:
entity_id: media_player.beosound_balance_32836899
```
## Services

### play_media services
Expand Down Expand Up @@ -461,59 +442,3 @@ Send a media_player command to Beolink leader.
### Service `bang_olufsen.reboot`

Reboot the device.

## Blueprints

### Announce where music has been joined from (Beolink)

A Blueprint for this scenario: https://youtu.be/AiZbrYQ6u48

Select the speaker you want to announce which other product it joins, when performing a long-press on the Play/Pause button.

Default phrase is “Joined {friendly name}”, but this can easily be modified to a different language, e.g: “Lytter med fra {friendly name}”.

Additionally it is possible to enable announcements when using a remote or the Bang & Olufsen app to expand.

Create an automation for each Mozart product that should announce when joining a different room.

[![Open your Home Assistant instance and show the blueprint import dialog with a specific blueprint pre-filled.](https://my.home-assistant.io/badges/blueprint_import.svg)](https://my.home-assistant.io/redirect/blueprint_import/?blueprint_url=https%3A%2F%2Fgist.github.com%2Fcklit%2Fe7126c9fda1195bd88bcaefb45fe493e)

### Control lights using Beoremote One BT (OUTDATED)

A Blueprint to easily set up light control with Beoremote One BT and a Mozart-based product.

Select your Mozart product and the light-bulbs or groups you want to control.

This Blueprint allows for 3 light "zones". See the setup for detailed information on how to control the 3 zones.

To use Light-commands, press “List” on your Beoremote One, navigate down to “Light” and press the center-button. From here, use the described buttons on the remote below to modify brightness.

[![Open your Home Assistant instance and show the blueprint import dialog with a specific blueprint pre-filled.](https://my.home-assistant.io/badges/blueprint_import.svg)](https://my.home-assistant.io/redirect/blueprint_import/?blueprint_url=https%3A%2F%2Fgist.github.com%2Fcklit%2F816e6fd144ff91559548e1bf0eb3bf84)

### Control shades using Beoremote One BT (OUTDATED)

A Blueprint to easily set up shade control with Beoremote One BT and a Mozart-based product.

Select your Mozart product and the shades you want to control.

This Blueprint allows for 3 "zones". See the setup for detailed information on how to control the 3 zones.

To use Control-commands, press “List” on your Beoremote One, navigate down to “Control” and press the center-button. From here, use the described buttons on the remote below to modify the position.

[![Open your Home Assistant instance and show the blueprint import dialog with a specific blueprint pre-filled.](https://my.home-assistant.io/badges/blueprint_import.svg)](https://my.home-assistant.io/redirect/blueprint_import/?blueprint_url=https%3A%2F%2Fgist.github.com%2Fcklit%2Fd81d36c525936ab8f9309a226287ff91)

### Control scenes using Light and Control menu items on Beoremote One BT (OUTDATED)

A Blueprint to set up scene control with Beoremote One BT and a Mozart-based product.

Select your Mozart product in the dropdown menu.

Enter the function (e.g. Light/Func1) you want to trigger the scene with. All functions are described in the Blueprint.

Select the action that should be triggered by the defined function. This can be any service call, e.g. scene.turn_on.

In case you have renamed the scenes on your remote, they will not match the documentation. To find the function name of a renamed button, enable the debug mode toggle. Every time a Light or Control item is activated, a notification with the name of the selected function will show up in the Home Assistant dashboard notification panel. We recommend to disable debug mode as soon as the automation is working as expected.

To activate a scene, press “List” on your Beoremote One BT, navigate down to “Light” or "Control" and press the right-arrow key. Navigate to the function you want to activate and confirm with the center-button.

[![Open your Home Assistant instance and show the blueprint import dialog with a specific blueprint pre-filled.](https://my.home-assistant.io/badges/blueprint_import.svg)](https://my.home-assistant.io/redirect/blueprint_import/?blueprint_url=https%3A%2F%2Fgist.github.com%2Fcklit%2Fd3ee25fa0576da38ca8dede75cf49c04)
42 changes: 23 additions & 19 deletions custom_components/bang_olufsen/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,51 +21,71 @@ class BangOlufsenSource:
name="Audio Streamer",
id="uriStreamer",
is_seekable=False,
is_enabled=True,
is_playable=True,
)
BLUETOOTH: Final[Source] = Source(
name="Bluetooth",
id="bluetooth",
is_seekable=False,
is_enabled=True,
is_playable=True,
)
CHROMECAST: Final[Source] = Source(
name="Chromecast built-in",
id="chromeCast",
is_seekable=False,
is_enabled=True,
is_playable=True,
)
LINE_IN: Final[Source] = Source(
name="Line-In",
id="lineIn",
is_seekable=False,
is_enabled=True,
is_playable=True,
)
SPDIF: Final[Source] = Source(
name="Optical",
id="spdif",
is_seekable=False,
is_enabled=True,
is_playable=True,
)
NET_RADIO: Final[Source] = Source(
name="B&O Radio",
id="netRadio",
is_seekable=False,
is_enabled=True,
is_playable=True,
)
DEEZER: Final[Source] = Source(
name="Deezer",
id="deezer",
is_seekable=True,
is_enabled=True,
is_playable=True,
)
TIDAL: Final[Source] = Source(
name="Tidal",
id="tidal",
is_seekable=True,
is_enabled=True,
is_playable=True,
)
USB_IN: Final[Source] = Source(
name="USB",
id="usbIn",
is_seekable=False,
is_enabled=True,
is_playable=True,
)
UNKNOWN: Final[Source] = Source(
name="Unknown Source",
id="unknown",
is_seekable=False,
is_enabled=False,
is_playable=False,
)


Expand Down Expand Up @@ -203,45 +223,29 @@ class WebsocketNotification(StrEnum):
PLAYING: Final[tuple] = ("started", "buffering", BANG_OLUFSEN_ON)
NOT_PLAYING: Final[tuple] = ("idle", "paused", "stopped", "ended", "unknown", "error")

# Sources on the device that should not be selectable by the user
HIDDEN_SOURCE_IDS: Final[tuple] = (
"airPlay",
"bluetooth",
"chromeCast",
"generator",
"local",
"dlna",
"qplay",
"wpl",
"pl",
"beolink",
"classicsAdapter",
"usbIn",
)

# Fallback sources to use in case of API failure.
FALLBACK_SOURCES: Final[SourceArray] = SourceArray(
items=[
Source(
id="uriStreamer",
is_enabled=True,
is_playable=False,
is_playable=True,
name="Audio Streamer",
type=SourceTypeEnum(value="uriStreamer"),
is_seekable=False,
),
Source(
id="bluetooth",
is_enabled=True,
is_playable=False,
is_playable=True,
name="Bluetooth",
type=SourceTypeEnum(value="bluetooth"),
is_seekable=False,
),
Source(
id="spotify",
is_enabled=True,
is_playable=False,
is_playable=True,
name="Spotify Connect",
type=SourceTypeEnum(value="spotify"),
is_seekable=True,
Expand Down
11 changes: 11 additions & 0 deletions custom_components/bang_olufsen/coordinator.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,9 @@ def __init__(
self._client.get_playback_progress_notifications(
self.on_playback_progress_notification
)
self._client.get_playback_source_notifications(
self.on_playback_source_notification
)
self._client.get_playback_state_notifications(
self.on_playback_state_notification
)
Expand Down Expand Up @@ -262,6 +265,14 @@ def on_playback_progress_notification(self, notification: PlaybackProgress) -> N
notification,
)

def on_playback_source_notification(self, notification: Source) -> None:
"""Send playback_source dispatch."""
async_dispatcher_send(
self.hass,
f"{self._unique_id}_{WebsocketNotification.PLAYBACK_SOURCE}",
notification,
)

def on_playback_state_notification(self, notification: RenderingState) -> None:
"""Send playback_state dispatch."""
async_dispatcher_send(
Expand Down
2 changes: 1 addition & 1 deletion custom_components/bang_olufsen/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,6 @@
"iot_class": "local_push",
"issue_tracker": "https://github.com/bang-olufsen/bang_olufsen-hacs/issues",
"requirements": ["mozart-api==4.1.1.116.0"],
"version": "2.5.5",
"version": "2.5.6",
"zeroconf": ["_bangolufsen._tcp.local."]
}
9 changes: 3 additions & 6 deletions custom_components/bang_olufsen/media_player.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,6 @@
CONNECTION_STATUS,
DOMAIN,
FALLBACK_SOURCES,
HIDDEN_SOURCE_IDS,
VALID_MEDIA_TYPES,
BangOlufsenMediaType,
BangOlufsenSource,
Expand Down Expand Up @@ -288,6 +287,7 @@ async def async_added_to_hass(self) -> None:
WebsocketNotification.PLAYBACK_ERROR: self._async_update_playback_error,
WebsocketNotification.PLAYBACK_METADATA: self._async_update_playback_metadata_and_beolink,
WebsocketNotification.PLAYBACK_PROGRESS: self._async_update_playback_progress,
WebsocketNotification.PLAYBACK_SOURCE: self._async_update_sources,
WebsocketNotification.PLAYBACK_STATE: self._async_update_playback_state,
WebsocketNotification.REMOTE_MENU_CHANGED: self._async_update_sources,
WebsocketNotification.SOURCE_CHANGE: self._async_update_source_change,
Expand Down Expand Up @@ -381,7 +381,7 @@ async def _async_update_name_and_beolink(self) -> None:

self.async_write_ha_state()

async def _async_update_sources(self) -> None:
async def _async_update_sources(self, _: Source | None = None) -> None:
"""Get sources for the specific product."""

# Audio sources
Expand All @@ -408,10 +408,7 @@ async def _async_update_sources(self) -> None:
self._audio_sources = {
source.id: source.name
for source in cast(list[Source], sources.items)
if source.is_enabled
and source.id
and source.name
and source.id not in HIDDEN_SOURCE_IDS
if source.is_enabled and source.id and source.name and source.is_playable
}

# Some sources are not Beolink expandable, meaning that they can't be joined by or expand to other Bang & Olufsen devices for a multi-room experience.
Expand Down
55 changes: 32 additions & 23 deletions custom_components/bang_olufsen/services.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,14 @@ beolink_join:
device:
integration: bang_olufsen
fields:
beolink_jid:
required: false
example: [email protected]
selector:
text:
jid_options:
collapsed: false
fields:
beolink_jid:
required: false
example: [email protected]
selector:
text:

beolink_expand:
target:
Expand All @@ -25,15 +28,18 @@ beolink_expand:
example: false
selector:
boolean:
beolink_jids:
required: false
example: >-
[
[email protected],
[email protected]
]
selector:
object:
jid_options:
collapsed: false
fields:
beolink_jids:
required: false
example: >-
[
[email protected],
[email protected]
]
selector:
object:

beolink_unexpand:
target:
Expand All @@ -43,15 +49,18 @@ beolink_unexpand:
device:
integration: bang_olufsen
fields:
beolink_jids:
required: true
example: >-
[
[email protected],
[email protected]
]
selector:
object:
jid_options:
collapsed: false
fields:
beolink_jids:
required: true
example: >-
[
[email protected],
[email protected]
]
selector:
object:

beolink_leave:
target:
Expand Down
Loading

0 comments on commit bfaa310

Please sign in to comment.