Skip to content

Commit f08faec

Browse files
committed
Add support for fetching play capabilities
1 parent b957e42 commit f08faec

6 files changed

Lines changed: 54 additions & 13 deletions

File tree

afsapi/__init__.py

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,30 +2,30 @@
22

33
from importlib.metadata import PackageNotFoundError, version
44

5-
from afsapi.exceptions import (
5+
from .api import AFSAPI
6+
from .exceptions import (
67
FSApiError,
78
FSConnectionError,
8-
FsNotImplementedError,
9+
FSNotImplementedError,
910
InvalidPinError,
1011
InvalidSessionError,
1112
OutOfRangeError,
1213
)
13-
from afsapi.models import (
14+
from .models import (
1415
Equaliser,
16+
PlayCaps,
1517
PlayControl,
1618
PlayerMode,
1719
PlayRepeatMode,
1820
PlayState,
1921
Preset,
2022
)
21-
from afsapi.nodes import (
23+
from .nodes import (
2224
Endpoint,
2325
ListEndpoint,
2426
Nodes,
2527
)
2628

27-
from .api import AFSAPI
28-
2929
try:
3030
__version__ = version(__name__)
3131
except PackageNotFoundError: # pragma: no cover
@@ -40,12 +40,13 @@
4040
"Equaliser",
4141
"FSApiError",
4242
"FSConnectionError",
43-
"FsNotImplementedError",
43+
"FSNotImplementedError",
4444
"InvalidPinError",
4545
"InvalidSessionError",
4646
"ListEndpoint",
4747
"Nodes",
4848
"OutOfRangeError",
49+
"PlayCaps",
4950
"PlayControl",
5051
"PlayRepeatMode",
5152
"PlayState",

afsapi/api.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,14 @@
1616
from afsapi.exceptions import (
1717
FSApiError,
1818
FSConnectionError,
19+
FSNodeBlockedError,
1920
InvalidPinError,
2021
InvalidSessionError,
2122
OutOfRangeError,
2223
)
2324
from afsapi.models import (
2425
Equaliser,
26+
PlayCaps,
2527
PlayControl,
2628
PlayerMode,
2729
PlayRepeatMode,
@@ -564,6 +566,13 @@ async def get_play_status(self) -> PlayState | None:
564566
return PlayState(status)
565567
return None
566568

569+
async def get_play_caps(self) -> PlayCaps | None:
570+
"""Get the supported play control capabilities of the device."""
571+
caps = await self.get(Nodes.caps)
572+
if caps is not None:
573+
return PlayCaps(caps)
574+
return None
575+
567576
async def get_play_name(self) -> str | None:
568577
"""Get the name of the played item."""
569578
return await self.get(Nodes.name)

afsapi/exceptions.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,11 @@ class FSApiError(Exception):
55
"""Base exception for all Frontier Silicon API errors."""
66

77

8-
class FsNotImplementedError(FSApiError):
8+
class FSNodeBlockedError(FSApiError):
9+
"""Exception raised when the device responds with FS_NODE_BLOCKED error."""
10+
11+
12+
class FSNotImplementedError(FSApiError):
913
"""Exception raised when an API operation is not implemented."""
1014

1115

afsapi/models.py

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
from __future__ import annotations
44

55
from dataclasses import dataclass
6-
from enum import IntEnum
6+
from enum import IntEnum, IntFlag, auto
77

88

99
class PlayState(IntEnum):
@@ -29,6 +29,31 @@ class PlayRepeatMode(IntEnum):
2929
REPEAT_ONE = 2
3030

3131

32+
class PlayCaps(IntFlag):
33+
"""Bitmask of supported playback control commands.
34+
35+
Returned by netRemote.play.caps endpoint.
36+
"""
37+
38+
Pause = auto()
39+
Stop = auto()
40+
SkipNext = auto()
41+
SkipPrevious = auto()
42+
FastForward = auto()
43+
Rewind = auto()
44+
Shuffle = auto()
45+
Repeat = auto()
46+
Seek = auto()
47+
ApplyFeedback = auto()
48+
Scrobbling = auto()
49+
AddPreset = auto()
50+
ThumbsUp = auto()
51+
ThumbsDown = auto()
52+
SkipForward = auto()
53+
SkipBackward = auto()
54+
RepeatOne = auto()
55+
56+
3257
class PlayControl(IntEnum):
3358
"""Enumeration of playback control commands."""
3459

afsapi/nodes.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,7 @@ class Nodes:
182182
mute: Endpoint[int] = Endpoint("netRemote.sys.audio.mute", "u8")
183183

184184
# --- play --------------------------------------------------------------
185+
caps: Endpoint[int] = Endpoint("netRemote.play.caps", "u32")
185186
status: Endpoint[int] = Endpoint("netRemote.play.status", "u8")
186187
name: Endpoint[str] = Endpoint("netRemote.play.info.name", "c8_array")
187188
control: Endpoint[int] = Endpoint("netRemote.play.control", "u8")

afsapi/response.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,10 @@
1313
if t.TYPE_CHECKING:
1414
from xml.etree import ElementTree as ET
1515

16-
from afsapi.exceptions import (
16+
from .exceptions import (
1717
FSApiError,
18-
FsNotImplementedError,
18+
FSNodeBlockedError,
19+
FSNotImplementedError,
1920
OutOfRangeError,
2021
)
2122

@@ -68,10 +69,10 @@ def to_exception(self) -> FSApiError:
6869

6970
if self == FSAPIStatus.FS_NODE_DOES_NOT_EXIST:
7071
msg = "FSAPI service not implemented on this device."
71-
return FsNotImplementedError(msg)
72+
return FSNotImplementedError(msg)
7273
if self == FSAPIStatus.FS_NODE_BLOCKED:
7374
msg = "Device is not in the correct mode"
74-
return FSApiError(msg)
75+
return FSNodeBlockedError(msg)
7576
if self == FSAPIStatus.FS_FAIL:
7677
msg = "Command failed. Value is not in range for this command."
7778
return OutOfRangeError(msg)

0 commit comments

Comments
 (0)