Skip to content
Merged
Show file tree
Hide file tree
Changes from 54 commits
Commits
Show all changes
62 commits
Select commit Hold shift + click to select a range
c331d50
media_player_all_features
rwrozelle Feb 28, 2025
b8abce2
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Feb 28, 2025
a977a4b
Remove commas from MediaPlayerCommand attributes
rwrozelle Feb 28, 2025
72918f2
Merge branch 'media_player_all_features' of https://github.com/rwroze…
rwrozelle Feb 28, 2025
18436fa
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Feb 28, 2025
40f5696
Update test_client.py
rwrozelle Feb 28, 2025
632f14a
Merge branch 'main' into media_player_all_features
bdraco Mar 8, 2025
15b2705
Merge branch 'main' into media_player_all_features
bdraco Mar 12, 2025
329eb15
Merge branch 'main' into media_player_all_features
bdraco Mar 12, 2025
b8a4e06
regen protobuf
bdraco Mar 12, 2025
35316b7
Merge branch 'esphome:main' into media_player_all_features
rwrozelle Mar 20, 2025
ef8f8f2
Merge branch 'esphome:main' into media_player_all_features
rwrozelle Apr 14, 2025
95f10db
With MA MP only needs turn_off_on Trait added
rwrozelle Apr 14, 2025
9c7a352
Merge branch 'media_player_all_features' of https://github.com/rwroze…
rwrozelle Apr 14, 2025
564f47d
Merge branch 'esphome:main' into media_player_all_features
rwrozelle Apr 17, 2025
3615415
Merge remote-tracking branch 'upstream/main' into media_player_all_fe…
rwrozelle Apr 29, 2025
bce91a6
Update api_pb2.py
rwrozelle Apr 29, 2025
3682eb4
Merge branch 'esphome:main' into media_player_all_features
rwrozelle May 7, 2025
f4622d0
Merge branch 'esphome:main' into media_player_all_features
rwrozelle May 12, 2025
bf1994e
Merge remote-tracking branch 'upstream/main' into media_player_all_fe…
rwrozelle May 22, 2025
edd1ec2
Update api_pb2.py
rwrozelle May 22, 2025
feb7c7f
Merge branch 'esphome:main' into media_player_all_features
rwrozelle Jun 13, 2025
182078b
Merge remote-tracking branch 'upstream/main' into media_player_all_fe…
rwrozelle Jun 29, 2025
348fbf2
Update api_pb2.py
rwrozelle Jun 29, 2025
91f955b
Merge remote-tracking branch 'upstream/main' into media_player_all_fe…
rwrozelle Jul 11, 2025
a607a22
Merge remote-tracking branch 'upstream/main' into media_player_all_fe…
rwrozelle Jul 14, 2025
7fcd728
Merge remote-tracking branch 'upstream/main' into media_player_all_fe…
rwrozelle Jul 19, 2025
21ee9ab
Generate protobuf
rwrozelle Jul 19, 2025
590455e
Merge remote-tracking branch 'upstream/main' into media_player_all_fe…
rwrozelle Jul 25, 2025
c6403f0
MediaPlayer feature_flags
rwrozelle Jul 25, 2025
4ac753b
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jul 25, 2025
28f81af
fix typo
rwrozelle Jul 25, 2025
6badbb6
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jul 25, 2025
8e59cfb
dos2unix fix
rwrozelle Jul 25, 2025
c2c6053
coderabbitai fix
rwrozelle Jul 25, 2025
8bd211a
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jul 25, 2025
11ca3dd
fix type
rwrozelle Jul 25, 2025
5f2a3f1
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jul 25, 2025
a88f867
fix import error
rwrozelle Jul 25, 2025
73e1ef1
Fix feature_flags_compat
rwrozelle Jul 25, 2025
8726b1b
fix test
rwrozelle Jul 25, 2025
fe2fd6c
Update to handle the turn_off_on
rwrozelle Jul 26, 2025
0267fbf
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jul 26, 2025
d992c89
Merge branch 'main' into media_player_all_features
bdraco Jul 26, 2025
edf7d28
fix feature_flags_compat
rwrozelle Jul 26, 2025
5af5952
Merge branch 'main' into media_player_all_features
rwrozelle Jul 26, 2025
6a4f245
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jul 26, 2025
c4a2397
Regenerate api_pb2.py
rwrozelle Jul 26, 2025
feb2da4
Merge branch 'main' into media_player_all_features
bdraco Jul 28, 2025
9f419d4
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jul 28, 2025
50708ba
Update aioesphomeapi/model.py
bdraco Jul 28, 2025
573438d
Merge remote-tracking branch 'origin/main' into media_player_all_feat…
bdraco Jul 28, 2025
a07610c
Merge remote-tracking branch 'origin/main' into media_player_all_feat…
bdraco Jul 28, 2025
7b3262d
make it more readable
bdraco Jul 28, 2025
57a350c
Update aioesphomeapi/api.proto
bdraco Jul 28, 2025
1a7096a
regen
bdraco Jul 28, 2025
c18dca7
Update aioesphomeapi/api.proto
bdraco Jul 28, 2025
c44cb6b
Update aioesphomeapi/api.proto
bdraco Jul 28, 2025
d974f87
update
bdraco Jul 28, 2025
eb82951
Update aioesphomeapi/api.proto
bdraco Jul 28, 2025
fed8281
update
bdraco Jul 28, 2025
eab4666
Merge remote-tracking branch 'upstream/main' into media_player_all_fe…
rwrozelle Jul 29, 2025
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
15 changes: 15 additions & 0 deletions aioesphomeapi/api.proto
Original file line number Diff line number Diff line change
Expand Up @@ -1297,13 +1297,26 @@ 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_ENQUEUE = 8;
MEDIA_PLAYER_COMMAND_REPEAT_ONE = 9;
MEDIA_PLAYER_COMMAND_REPEAT_OFF = 10;
MEDIA_PLAYER_COMMAND_CLEAR_PLAYLIST = 11;
MEDIA_PLAYER_COMMAND_TURN_ON = 12;
MEDIA_PLAYER_COMMAND_TURN_OFF = 13;
}
enum MediaPlayerFormatPurpose {
MEDIA_PLAYER_FORMAT_PURPOSE_DEFAULT = 0;
Expand Down Expand Up @@ -1338,6 +1351,8 @@ message ListEntitiesMediaPlayerResponse {
repeated MediaPlayerSupportedFormat supported_formats = 9;

uint32 device_id = 10 [(field_ifdef) = "USE_DEVICES"];

uint32 feature_flags = 11;
}
message MediaPlayerStateResponse {
option (id) = 64;
Expand Down
424 changes: 212 additions & 212 deletions aioesphomeapi/api_pb2.py

Large diffs are not rendered by default.

58 changes: 58 additions & 0 deletions aioesphomeapi/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -873,11 +873,42 @@ class ValveState(EntityState):


# ==================== MEDIA PLAYER ====================
class MediaPlayerEntityFeature(enum.IntFlag):
"""Supported features of the media player entity."""

PAUSE = 1 << 0
SEEK = 1 << 1
VOLUME_SET = 1 << 2
VOLUME_MUTE = 1 << 3
PREVIOUS_TRACK = 1 << 4
NEXT_TRACK = 1 << 5

TURN_ON = 1 << 7
TURN_OFF = 1 << 8
PLAY_MEDIA = 1 << 9
VOLUME_STEP = 1 << 10
SELECT_SOURCE = 1 << 11
STOP = 1 << 12
CLEAR_PLAYLIST = 1 << 13
PLAY = 1 << 14
SHUFFLE_SET = 1 << 15
SELECT_SOUND_MODE = 1 << 16
BROWSE_MEDIA = 1 << 17
REPEAT_SET = 1 << 18
GROUPING = 1 << 19
MEDIA_ANNOUNCE = 1 << 20
MEDIA_ENQUEUE = 1 << 21
SEARCH_MEDIA = 1 << 22


class MediaPlayerState(APIIntEnum):
NONE = 0
IDLE = 1
PLAYING = 2
PAUSED = 3
ANNOUNCING = 4
OFF = 5
ON = 6


class MediaPlayerCommand(APIIntEnum):
Expand All @@ -886,6 +917,15 @@ class MediaPlayerCommand(APIIntEnum):
STOP = 2
MUTE = 3
UNMUTE = 4
TOGGLE = 5
VOLUME_UP = 6
VOLUME_DOWN = 7
ENQUEUE = 8
REPEAT_ONE = 9
REPEAT_OFF = 10
CLEAR_PLAYLIST = 11
TURN_ON = 12
TURN_OFF = 13


class MediaPlayerFormatPurpose(APIIntEnum):
Expand Down Expand Up @@ -922,6 +962,24 @@ class MediaPlayerInfo(EntityInfo):
supported_formats: list[MediaPlayerSupportedFormat] = converter_field(
default_factory=list, converter=MediaPlayerSupportedFormat.convert_list
)
feature_flags: int = 0

def feature_flags_compat(self, api_version: APIVersion) -> int:
if api_version < APIVersion(1, 11):
flags = (
MediaPlayerEntityFeature.PLAY_MEDIA
| MediaPlayerEntityFeature.BROWSE_MEDIA
| MediaPlayerEntityFeature.STOP
| MediaPlayerEntityFeature.VOLUME_SET
| MediaPlayerEntityFeature.VOLUME_MUTE
| MediaPlayerEntityFeature.MEDIA_ANNOUNCE
)
if self.supports_pause:
flags |= MediaPlayerEntityFeature.PAUSE | MediaPlayerEntityFeature.PLAY

return flags

return self.feature_flags


@_frozen_dataclass_decorator
Expand Down
43 changes: 43 additions & 0 deletions tests/test_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@
LightState,
LockEntityState,
LockInfo,
MediaPlayerEntityFeature,
MediaPlayerEntityState,
MediaPlayerInfo,
NoiseEncryptionSetKeyResponse as NoiseEncryptionSetKeyResponseModel,
Expand Down Expand Up @@ -792,6 +793,7 @@ def test_media_player_supported_format_convert_list() -> None:
"sample_bytes": 2,
}
],
"feature_flags": 0,
}
) == MediaPlayerInfo(
supports_pause=False,
Expand All @@ -804,9 +806,50 @@ def test_media_player_supported_format_convert_list() -> None:
sample_bytes=2,
)
],
feature_flags=0,
)


def test_media_player_feature_flags_compat() -> None:
"""Test feature flags compatibility across API versions"""
info = MediaPlayerInfo(
supports_pause=False,
supported_formats=[
MediaPlayerSupportedFormat(
format="flac",
sample_rate=48000,
num_channels=2,
purpose=1,
sample_bytes=2,
)
],
feature_flags=999999, # Different from calculated compatibility flags
)
# For API version < 1.11, should return calculated compatibility flags
compat_flags = info.feature_flags_compat(APIVersion(1, 10))
expected_compat = (
MediaPlayerEntityFeature.PLAY_MEDIA
| MediaPlayerEntityFeature.BROWSE_MEDIA
| MediaPlayerEntityFeature.STOP
| MediaPlayerEntityFeature.VOLUME_SET
| MediaPlayerEntityFeature.VOLUME_MUTE
| MediaPlayerEntityFeature.MEDIA_ANNOUNCE
)
assert compat_flags == expected_compat

# For API version >= 1.11, should return feature_flags directly
direct_flags = info.feature_flags_compat(APIVersion(1, 11))
assert direct_flags == 999999

# Test with supports_pause=True to verify PAUSE|PLAY flags are added
info_with_pause = MediaPlayerInfo(supports_pause=True, feature_flags=888888)
compat_with_pause = info_with_pause.feature_flags_compat(APIVersion(1, 10))
expected_with_pause = (
expected_compat | MediaPlayerEntityFeature.PAUSE | MediaPlayerEntityFeature.PLAY
)
assert compat_with_pause == expected_with_pause


def test_device_info_area_field() -> None:
"""Test DeviceInfo with area field set."""
device_info = DeviceInfo(
Expand Down
Loading