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

Extend Functionality of Media_Player #911

Open
wants to merge 38 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 36 commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
1914f27
Add Support for Next/Previous Track and Turn Off/On
bobrozelle May 18, 2024
21a57d0
Add additional optional features for Playlist
bobrozelle May 25, 2024
1699d2b
Fix Announcement Type
bobrozelle May 25, 2024
633e149
Fix Enqueue
bobrozelle May 26, 2024
4888fe9
Merge branch 'main' of https://github.com/rwrozelle/aioesphomeapi
bobrozelle May 28, 2024
6e2258a
Merge branch 'esphome:main' into main
rwrozelle Jun 2, 2024
373e826
Merge branch 'esphome:main' into main
rwrozelle Jun 8, 2024
b0c8106
media_player updates
bobrozelle Jun 9, 2024
fe9a3ae
Merge branch 'main' of https://github.com/rwrozelle/aioesphomeapi
bobrozelle Jun 9, 2024
ccaab5c
Add duration and position
bobrozelle Jun 17, 2024
aa8c74e
Merge branch 'main' of https://github.com/rwrozelle/aioesphomeapi
bobrozelle Jun 21, 2024
0d48853
MRM group members
bobrozelle Jun 21, 2024
fd8b25b
Merge branch 'esphome:main' into main
rwrozelle Jun 27, 2024
64653aa
Remove mrm as parameter to play_media
bobrozelle Jun 27, 2024
b916d4f
Merge branch 'esphome:main' into main
rwrozelle Jul 4, 2024
8860fe6
Merge branch 'esphome:main' into main
rwrozelle Jul 13, 2024
d36e0f5
Merge branch 'esphome:main' into main
rwrozelle Jul 26, 2024
b5c9cb5
Add blank lines
rwrozelle Jul 28, 2024
925f0e9
Update test_client.py
rwrozelle Jul 28, 2024
6936b1e
Update model.py
rwrozelle Jul 28, 2024
4d3da49
Update test_client.py
rwrozelle Jul 28, 2024
c9ae2af
Update test_client.py
rwrozelle Jul 28, 2024
1bdd95c
Update test_client.py
rwrozelle Jul 28, 2024
25e84f3
Update test_client.py
rwrozelle Jul 28, 2024
fcf8b06
Update test_client.py
rwrozelle Jul 28, 2024
bad0fb8
use protoc 3.19.6
rwrozelle Jul 29, 2024
55b480f
Update test_client.py
rwrozelle Jul 29, 2024
478db97
Update test_client.py
rwrozelle Jul 29, 2024
de036bc
Fix Media_Player_State enum
rwrozelle Jul 30, 2024
e740562
Update model.py
rwrozelle Jul 30, 2024
e92395b
Merge branch 'esphome:main' into main
rwrozelle Aug 1, 2024
6217f7d
Merge remote-tracking branch 'upstream/main'
rwrozelle Aug 15, 2024
6d26ed7
Update api_pb2.py
rwrozelle Aug 15, 2024
f560cb9
Merge remote-tracking branch 'upstream/main'
rwrozelle Aug 31, 2024
2dea139
Update api_pb2.py
rwrozelle Aug 31, 2024
b0dd6b6
Merge remote-tracking branch 'upstream/main'
rwrozelle Sep 20, 2024
9ce8c22
Update api_pb2.py
rwrozelle Sep 20, 2024
cbcc04c
Merge branch 'main' into main
bdraco Oct 13, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 35 additions & 1 deletion aioesphomeapi/api.proto
Original file line number Diff line number Diff line change
Expand Up @@ -1126,13 +1126,32 @@ enum MediaPlayerState {
MEDIA_PLAYER_STATE_IDLE = 1;
MEDIA_PLAYER_STATE_PLAYING = 2;
MEDIA_PLAYER_STATE_PAUSED = 3;
MEDIA_PLAYER_STATE_ANNOUNCING = 4;
MEDIA_PLAYER_STATE_OFF = 5;
MEDIA_PLAYER_STATE_ON = 6;

}
enum MediaPlayerCommand {
MEDIA_PLAYER_COMMAND_PLAY = 0;
MEDIA_PLAYER_COMMAND_PAUSE = 1;
MEDIA_PLAYER_COMMAND_STOP = 2;
MEDIA_PLAYER_COMMAND_MUTE = 3;
MEDIA_PLAYER_COMMAND_UNMUTE = 4;
MEDIA_PLAYER_COMMAND_TOGGLE = 5;
MEDIA_PLAYER_COMMAND_VOLUME_UP = 6;
MEDIA_PLAYER_COMMAND_VOLUME_DOWN = 7;
MEDIA_PLAYER_COMMAND_NEXT_TRACK = 8;
MEDIA_PLAYER_COMMAND_PREVIOUS_TRACK = 9;
MEDIA_PLAYER_COMMAND_TURN_ON = 10;
MEDIA_PLAYER_COMMAND_TURN_OFF = 11;
MEDIA_PLAYER_COMMAND_CLEAR_PLAYLIST = 12;
MEDIA_PLAYER_COMMAND_SHUFFLE = 13;
MEDIA_PLAYER_COMMAND_UNSHUFFLE = 14;
MEDIA_PLAYER_COMMAND_REPEAT_OFF = 15;
MEDIA_PLAYER_COMMAND_REPEAT_ONE = 16;
MEDIA_PLAYER_COMMAND_REPEAT_ALL = 17;
MEDIA_PLAYER_COMMAND_JOIN = 18;
MEDIA_PLAYER_COMMAND_UNJOIN = 19;
}
enum MediaPlayerFormatPurpose {
MEDIA_PLAYER_FORMAT_PURPOSE_DEFAULT = 0;
Expand Down Expand Up @@ -1162,8 +1181,10 @@ message ListEntitiesMediaPlayerResponse {
EntityCategory entity_category = 7;

bool supports_pause = 8;

repeated MediaPlayerSupportedFormat supported_formats = 9;
bool supports_turn_off_on = 10;
bool supports_grouping = 11;
bool supports_next_previous_track = 12;
Comment on lines +1185 to +1187
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Validate Field Numbers and Dependency Management in ListEntitiesMediaPlayerResponse

The fields supports_turn_off_on, supports_grouping, and supports_next_previous_track expand the capabilities of the media player entities. Ensure that:

  • The field numbers (10, 11, 12) do not conflict with existing fields.
  • The implementation correctly handles scenarios when these features are unsupported by certain devices.

Verify the field numbering and update the documentation to reflect these new capabilities.

}
message MediaPlayerStateResponse {
option (id) = 64;
Expand All @@ -1174,6 +1195,13 @@ message MediaPlayerStateResponse {
MediaPlayerState state = 2;
float volume = 3;
bool muted = 4;
string repeat = 5;
bool shuffle = 6;
string artist = 7;
string album = 8;
string title = 9;
int32 duration = 10;
int32 position = 11;
Comment on lines +1198 to +1204
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Refine Data Types for repeat, duration, and position in MediaPlayerStateResponse

  • Repeat Field: The repeat field is currently a string. It would be more robust to define an enum MediaPlayerRepeatMode to represent repeat states, enhancing type safety and preventing invalid values.

  • Duration and Position Fields: As durations and positions can't be negative, consider using uint32 instead of int32.

  1. Define the MediaPlayerRepeatMode enum:

    enum MediaPlayerRepeatMode {
      MEDIA_PLAYER_REPEAT_OFF = 0;
      MEDIA_PLAYER_REPEAT_ONE = 1;
      MEDIA_PLAYER_REPEAT_ALL = 2;
    }
  2. Update the repeat field:

    - string repeat = 5;
    + MediaPlayerRepeatMode repeat = 5;
  3. Change duration and position to unsigned integers:

    - int32 duration = 10;
    - int32 position = 11;
    + uint32 duration = 10;
    + uint32 position = 11;

}
message MediaPlayerCommandRequest {
option (id) = 65;
Expand All @@ -1194,6 +1222,12 @@ message MediaPlayerCommandRequest {

bool has_announcement = 8;
bool announcement = 9;

bool has_enqueue = 10;
string enqueue = 11;

bool has_group_members = 12;
string group_members = 13;
Comment on lines +1226 to +1230
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adjust Data Types for enqueue and group_members Fields in MediaPlayerCommandRequest

  • Enqueue Field: If enqueue is intended to handle multiple media URLs, it should be a repeated string. If it's a single URL, consider renaming it to media_url for clarity.

  • Group Members Field: If group_members represents multiple members, it should be a repeated string.

Suggested changes:

  1. Update enqueue field:

    - bool has_enqueue = 10;
    - string enqueue = 11;
    + bool has_enqueue = 10;
    + repeated string enqueue = 11;
  2. Update group_members field:

    - bool has_group_members = 12;
    - string group_members = 13;
    + bool has_group_members = 12;
    + repeated string group_members = 13;

Ensure that the implementation handles these fields appropriately in the codebase.

Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
bool has_enqueue = 10;
string enqueue = 11;
bool has_group_members = 12;
string group_members = 13;
bool has_enqueue = 10;
repeated string enqueue = 11;
bool has_group_members = 12;
repeated string group_members = 13;

}

// ==================== BLUETOOTH ====================
Expand Down
18 changes: 18 additions & 0 deletions aioesphomeapi/api_pb2.py

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions aioesphomeapi/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -1207,6 +1207,8 @@ def media_player_command(
volume: float | None = None,
media_url: str | None = None,
announcement: bool | None = None,
enqueue: str | None = None,
group_members: str | None = None,
) -> None:
req = MediaPlayerCommandRequest(key=key)
if command is not None:
Expand All @@ -1221,6 +1223,12 @@ def media_player_command(
if announcement is not None:
req.announcement = announcement
req.has_announcement = True
if enqueue is not None:
req.enqueue = enqueue
req.has_enqueue = True
if group_members is not None:
req.group_members = group_members
req.has_group_members = True
self._get_connection().send_message(req)

def text_command(self, key: int, state: str) -> None:
Expand Down
30 changes: 30 additions & 0 deletions aioesphomeapi/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -811,6 +811,9 @@ class MediaPlayerState(APIIntEnum):
IDLE = 1
PLAYING = 2
PAUSED = 3
ANNOUNCING = 4
OFF = 5
ON = 6
Comment on lines +814 to +816
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reconsider including OFF and ON states in MediaPlayerState

The addition of OFF and ON states to MediaPlayerState may blur the distinction between device power states and media playback states. Typically, MediaPlayerState represents the playback status (e.g., playing, paused). Consider handling power states separately to maintain a clear separation of concerns.



class MediaPlayerCommand(APIIntEnum):
Expand All @@ -819,6 +822,22 @@ class MediaPlayerCommand(APIIntEnum):
STOP = 2
MUTE = 3
UNMUTE = 4
TOGGLE = 5
VOLUME_UP = 6
VOLUME_DOWN = 7
NEXT_TRACK = 8
PREVIOUS_TRACK = 9
TURN_ON = 10
TURN_OFF = 11

CLEAR_PLAYLIST = 12
SHUFFLE = 13
UNSHUFFLE = 14
REPEAT_OFF = 15
REPEAT_ONE = 16
REPEAT_ALL = 17
JOIN = 18
UNJOIN = 19


class MediaPlayerFormatPurpose(APIIntEnum):
Expand Down Expand Up @@ -851,6 +870,9 @@ def convert_list(cls, value: list[Any]) -> list[MediaPlayerSupportedFormat]:
@_frozen_dataclass_decorator
class MediaPlayerInfo(EntityInfo):
supports_pause: bool = False
supports_next_previous_track: bool = False
supports_turn_off_on: bool = False
supports_grouping: bool = False

supported_formats: list[MediaPlayerSupportedFormat] = converter_field(
default_factory=list, converter=MediaPlayerSupportedFormat.convert_list
Expand All @@ -866,6 +888,14 @@ class MediaPlayerEntityState(EntityState):
default=0.0, converter=fix_float_single_double_conversion
)
muted: bool = False
repeat: str = ""
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use an enum for repeat to ensure type safety

The repeat attribute in MediaPlayerEntityState is currently a string. To prevent typos and enforce valid repeat modes, define a MediaPlayerRepeatMode enum (e.g., OFF, ONE, ALL) and use it for the repeat attribute.

Define the enum:

class MediaPlayerRepeatMode(APIIntEnum):
    OFF = 0
    ONE = 1
    ALL = 2

Update the repeat attribute:

-repeat: str = ""
+repeat: MediaPlayerRepeatMode | None = converter_field(
+    default=MediaPlayerRepeatMode.OFF, converter=MediaPlayerRepeatMode.convert
+)

shuffle: bool = False

artist: str = ""
album: str = ""
title: str = ""
duration: int = 0
position: int = 0


# ==================== ALARM CONTROL PANEL ====================
Expand Down
24 changes: 24 additions & 0 deletions tests/test_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -798,6 +798,16 @@ async def test_select_command(
dict(key=1, volume=1.0),
dict(key=1, has_volume=True, volume=1.0),
),
(
dict(key=1, media_url="http://example.com", enqueue="replace"),
dict(
key=1,
has_media_url=True,
media_url="http://example.com",
has_enqueue=True,
enqueue="replace",
),
Comment on lines +801 to +809
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fix syntax error in dictionary definition.

There is a missing comma at the end of line 803.

-                media_url="http://example.com" 
+                media_url="http://example.com",
Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
(
dict(key=1, media_url="http://example.com", enqueue="replace"),
dict(
key=1,
has_media_url=True,
media_url="http://example.com",
has_enqueue=True,
enqueue="replace",
),
(
dict(key=1, media_url="http://example.com", enqueue="replace"),
dict(
key=1,
has_media_url=True,
media_url="http://example.com",
has_enqueue=True,
enqueue="replace",
),

),
(
dict(key=1, media_url="http://example.com"),
dict(key=1, has_media_url=True, media_url="http://example.com"),
Expand All @@ -812,6 +822,20 @@ async def test_select_command(
announcement=True,
),
),
(
dict(
key=1,
command=MediaPlayerCommand.JOIN,
group_members="media_player.media_player_2,",
),
dict(
key=1,
has_command=True,
command=MediaPlayerCommand.JOIN,
has_group_members=True,
group_members="media_player.media_player_2,",
),
Comment on lines +825 to +837
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review: Syntax Error and Logic Check for Group Members Parameter

The test case for the media player command with command and group_members parameters has a trailing comma in the group_members string, which might not be necessary unless the API explicitly requires it. This could potentially lead to errors or unexpected behavior when parsing the group members on the receiving end.

Consider removing the trailing comma for clarity and to prevent potential parsing issues:

-                group_members="media_player.media_player_2,",
+                group_members="media_player.media_player_2"
Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
(
dict(
key=1,
command=MediaPlayerCommand.JOIN,
group_members="media_player.media_player_2,",
),
dict(
key=1,
has_command=True,
command=MediaPlayerCommand.JOIN,
has_group_members=True,
group_members="media_player.media_player_2,",
),
(
dict(
key=1,
command=MediaPlayerCommand.JOIN,
group_members="media_player.media_player_2"
),
dict(
key=1,
has_command=True,
command=MediaPlayerCommand.JOIN,
has_group_members=True,
group_members="media_player.media_player_2"
),

),
],
)
async def test_media_player_command(
Expand Down
Loading