Skip to content

Commit

Permalink
[ 1.0.22 ] Added service "Music Service Station List" - Gets a list o…
Browse files Browse the repository at this point in the history
…f your stored stations from the specified music service (e.g. PANDORA, etc).
  • Loading branch information
thlucas1 committed Dec 17, 2023
1 parent 54b1544 commit 774c838
Show file tree
Hide file tree
Showing 9 changed files with 168 additions and 22 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ Change are listed in reverse chronological order (newest to oldest).

<span class="changelog">

###### [ 1.0.22 ] - 2023/12/17

* Added service "Music Service Station List" - Gets a list of your stored stations from the specified music service (e.g. PANDORA, etc).

###### [ 1.0.21 ] - 2023/12/16

* Updated underlying `bosesoundtouchapi` package requirement to version 1.0.35.
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ The following custom services are also supplied by this integration.
- Play URL: Play media content URL on a SoundTouch device. Note that this is limited to ST10,20,30 devices, as Bose ST300 does not support notifications (AFAIK).
- Get Preset List: Retrieves the list of presets defined to the device.
- Get Recent List: Retrieves the list of recently played items defined to the device.
- Get Music Service Station List: Retrieves a list of stored stations for your music service account (e.g. PANDORA, etc).
- Reboot Device: Reboots the operating system of the SoundTouch device.
- Remote Keypress: Simulates the press and release of a key on the SoundTouch device remote control.
- Snapshot Restore: Restore SoundTouch device settings from a snapshot.
Expand Down
66 changes: 47 additions & 19 deletions custom_components/soundtouchplus/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,14 @@
DEFAULT_PORT,
DEFAULT_PORT_WEBSOCKET,
SERVICE_AUDIO_TONE_LEVELS,
SERVICE_MUSICSERVICE_STATION_LIST,
SERVICE_PLAY_CONTENTITEM,
SERVICE_PLAY_HANDOFF,
SERVICE_PLAY_TTS,
SERVICE_PLAY_URL,
SERVICE_PRESETLIST,
SERVICE_PRESET_LIST,
SERVICE_REBOOT_DEVICE,
SERVICE_RECENTLIST,
SERVICE_RECENT_LIST,
SERVICE_REMOTE_KEYPRESS,
SERVICE_SNAPSHOT_RESTORE,
SERVICE_SNAPSHOT_STORE
Expand Down Expand Up @@ -88,6 +89,15 @@
}
)

SERVICE_MUSICSERVICE_STATION_LIST_SCHEMA = vol.Schema(
{
vol.Required("entity_id"): cv.entity_id,
vol.Required("source"): cv.string,
vol.Required("source_account"): cv.string,
vol.Optional("sort_type", default='stationName'): cv.string
}
)

SERVICE_PLAY_CONTENTITEM_SCHEMA = vol.Schema(
{
vol.Required("entity_id"): cv.entity_id,
Expand Down Expand Up @@ -136,7 +146,7 @@
}
)

SERVICE_PRESETLIST_SCHEMA = vol.Schema(
SERVICE_PRESET_LIST_SCHEMA = vol.Schema(
{
vol.Required("entity_id"): cv.entity_id,
}
Expand All @@ -149,7 +159,7 @@
}
)

SERVICE_RECENTLIST_SCHEMA = vol.Schema(
SERVICE_RECENT_LIST_SCHEMA = vol.Schema(
{
vol.Required("entity_id"): cv.entity_id,
}
Expand Down Expand Up @@ -368,20 +378,29 @@ async def service_handle_getlist(service: ServiceCall) -> ServiceResponse:
response:dict = {}

# process service request.
if service.service == SERVICE_PRESETLIST:
if service.service == SERVICE_MUSICSERVICE_STATION_LIST:

# get list of music service stations.
source = service.data.get("source")
source_account = service.data.get("source_account")
sort_type = service.data.get("sort_type")
results:NavigateResponse = await hass.async_add_executor_job(player.service_musicservice_station_list, source, source_account, sort_type)
response = results.ToDictionary()

elif service.service == SERVICE_PRESET_LIST:

# get list of presets defined for the device.
presetList:PresetList = await hass.async_add_executor_job(player.service_preset_list)
response = presetList.ToDictionary()
# get list of presets defined for the device.
results:PresetList = await hass.async_add_executor_job(player.service_preset_list)
response = results.ToDictionary()

elif service.service == SERVICE_RECENTLIST:
elif service.service == SERVICE_RECENT_LIST:

# get list of recently played items defined for the device.
recentList:RecentList = await hass.async_add_executor_job(player.service_recent_list)
response = recentList.ToDictionary()
# get list of recently played items defined for the device.
results:RecentList = await hass.async_add_executor_job(player.service_recent_list)
response = results.ToDictionary()

# build list of items to return.
_logsi.LogDictionary(SILevel.Verbose, "Service Response data", response, prettyPrint=True)
_logsi.LogDictionary(SILevel.Verbose, "Service Response data: '%s'" % (service.service), response, prettyPrint=True)
return response

except SoundTouchWarning as ex: pass # should already be logged
Expand Down Expand Up @@ -448,6 +467,15 @@ def _GetEntityFromServiceData(hass:HomeAssistant, service:ServiceCall, field_id:
schema=SERVICE_AUDIO_TONE_LEVELS_SCHEMA,
)

_logsi.LogObject(SILevel.Verbose, STAppMessages.MSG_SERVICE_REQUEST_REGISTER % SERVICE_MUSICSERVICE_STATION_LIST, SERVICE_MUSICSERVICE_STATION_LIST_SCHEMA)
hass.services.async_register(
DOMAIN,
SERVICE_MUSICSERVICE_STATION_LIST,
service_handle_getlist,
schema=SERVICE_MUSICSERVICE_STATION_LIST_SCHEMA,
supports_response=SupportsResponse.ONLY,
)

_logsi.LogObject(SILevel.Verbose, STAppMessages.MSG_SERVICE_REQUEST_REGISTER % SERVICE_PLAY_CONTENTITEM, SERVICE_PLAY_CONTENTITEM_SCHEMA)
hass.services.async_register(
DOMAIN,
Expand Down Expand Up @@ -480,12 +508,12 @@ def _GetEntityFromServiceData(hass:HomeAssistant, service:ServiceCall, field_id:
schema=SERVICE_PLAY_URL_SCHEMA,
)

_logsi.LogObject(SILevel.Verbose, STAppMessages.MSG_SERVICE_REQUEST_REGISTER % SERVICE_PRESETLIST, SERVICE_PRESETLIST_SCHEMA)
_logsi.LogObject(SILevel.Verbose, STAppMessages.MSG_SERVICE_REQUEST_REGISTER % SERVICE_PRESET_LIST, SERVICE_PRESET_LIST_SCHEMA)
hass.services.async_register(
DOMAIN,
SERVICE_PRESETLIST,
SERVICE_PRESET_LIST,
service_handle_getlist,
schema=SERVICE_PRESETLIST_SCHEMA,
schema=SERVICE_PRESET_LIST_SCHEMA,
supports_response=SupportsResponse.ONLY,
)

Expand All @@ -497,12 +525,12 @@ def _GetEntityFromServiceData(hass:HomeAssistant, service:ServiceCall, field_id:
schema=SERVICE_REBOOT_DEVICE_SCHEMA,
)

_logsi.LogObject(SILevel.Verbose, STAppMessages.MSG_SERVICE_REQUEST_REGISTER % SERVICE_RECENTLIST, SERVICE_RECENTLIST_SCHEMA)
_logsi.LogObject(SILevel.Verbose, STAppMessages.MSG_SERVICE_REQUEST_REGISTER % SERVICE_RECENT_LIST, SERVICE_RECENT_LIST_SCHEMA)
hass.services.async_register(
DOMAIN,
SERVICE_RECENTLIST,
SERVICE_RECENT_LIST,
service_handle_getlist,
schema=SERVICE_RECENTLIST_SCHEMA,
schema=SERVICE_RECENT_LIST_SCHEMA,
supports_response=SupportsResponse.ONLY,
)

Expand Down
5 changes: 3 additions & 2 deletions custom_components/soundtouchplus/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,14 @@

# custom service names.
SERVICE_AUDIO_TONE_LEVELS = "audio_tone_levels"
SERVICE_MUSICSERVICE_STATION_LIST = "musicservice_station_list"
SERVICE_PLAY_CONTENTITEM = "play_contentitem"
SERVICE_PLAY_HANDOFF = "play_handoff"
SERVICE_PLAY_TTS = "play_tts"
SERVICE_PLAY_URL = "play_url"
SERVICE_PRESETLIST = "preset_list"
SERVICE_PRESET_LIST = "preset_list"
SERVICE_REBOOT_DEVICE = "reboot_device"
SERVICE_RECENTLIST = "recent_list"
SERVICE_RECENT_LIST = "recent_list"
SERVICE_REMOTE_KEYPRESS = "remote_keypress"
SERVICE_SNAPSHOT_RESTORE = "snapshot_restore"
SERVICE_SNAPSHOT_STORE = "snapshot_store"
2 changes: 1 addition & 1 deletion custom_components/soundtouchplus/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,6 @@
"smartinspectPython==3.0.30",
"bosesoundtouchapi==1.0.35"
],
"version": "1.0.21",
"version": "1.0.22",
"zeroconf": [ "_soundtouch._tcp.local." ]
}
28 changes: 28 additions & 0 deletions custom_components/soundtouchplus/media_player.py
Original file line number Diff line number Diff line change
Expand Up @@ -1155,6 +1155,34 @@ def service_audio_tone_levels(self, bassLevel:int, trebleLevel:int):
self._client.SetAudioProductToneControls(config)


def service_musicservice_station_list(self, source:str, sourceAccount:str, sortType:str) -> NavigateResponse:
"""
Retrieves a list of your stored stations from the specified music service (e.g. PANDORA, etc).
Args:
source (str):
Music service source to navigate (e.g. "PANDORA", "STORED_MUSIC", etc).
The value is case-sensitive, and should normally be UPPER case.
sourceAccount (str):
Music service source account (e.g. the music service user-id).
sortType (str):
Sort type used by the Music Service to sort the returned items by.
The value is case-sensitive.
Returns:
A `NavigateResponse` instance that contain the results.
"""
if _logsi.IsOn(SILevel.Verbose):
parms:dict = {}
parms['source'] = source
parms['sourceAccount'] = sourceAccount
parms['sortType'] = sortType
_logsi.LogDictionary(SILevel.Verbose, STAppMessages.MSG_PLAYER_COMMAND % ("service_musicservice_station_list", self.name, self.entity_id), parms)

criteria:Navigate = Navigate(source, sourceAccount, sortType=sortType)
return self._client.GetMusicServiceStations(criteria)


def service_play_contentitem(self, name:str, source:str, sourceAccount:str, itemType:str, location:str, containerArt:str, isPresetable:bool):
"""
Play media content from a content item source (e.g. TUNEIN station, etc) on a SoundTouch device.
Expand Down
40 changes: 40 additions & 0 deletions custom_components/soundtouchplus/services.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,46 @@ audio_tone_levels:
step: 25
mode: slider

musicservice_station_list:
name: Get Music Service Station List
description: Retrieves the list of your stored stations from the specified music service (e.g. PANDORA, etc).
fields:
entity_id:
name: Entity ID
description: Entity ID of the SoundTouch device that will query the specified music service.
example: "media_player.soundtouch_livingroom"
required: true
selector:
entity:
integration: soundtouchplus
domain: media_player
source:
name: Source
description: Music service source to navigate (e.g. 'PANDORA', etc); the value is case-sensitive, and should normally be UPPER case.
example: "PANDORA"
required: true
selector:
text:
source_account:
name: Source Account
description: Music service source account (e.g. the music service user-id). Default is none.
example: ""
required: false
selector:
text:
sort_type:
name: Sort Type
description: Sort type used by the Music Service to sort the returned items by; the value is case-sensitive.
example: "stationName"
required: false
selector:
select:
mode: dropdown
sort: true
options:
- dateCreated
- stationName

play_contentitem:
name: Play Content Item
description: Play media content from a content item source (e.g. TUNEIN station, etc) on a SoundTouch device.
Expand Down
22 changes: 22 additions & 0 deletions custom_components/soundtouchplus/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,28 @@
}
}
},
"musicservice_station_list": {
"name": "Get Music Service Station List",
"description": "Retrieves the list of your stored stations from the specified music service (e.g. PANDORA, etc).",
"fields": {
"entity_id": {
"name": "Entity ID",
"description": "Entity ID of the SoundTouch device that will query the specified music service."
},
"source": {
"name": "Source",
"description": "Music service source to navigate (e.g. 'PANDORA', etc); the value is case-sensitive, and should normally be UPPER case."
},
"source_account": {
"name": "Source Account",
"description": "Music service source account (e.g. the music service user-id). Default is none."
},
"sort_type": {
"name": "Sort Type",
"description": "Sort type used by the Music Service to sort the returned items by ('dateCreated', 'stationName'); the value is case-sensitive."
}
}
},
"play_contentitem": {
"name": "Play Content Item",
"description": "Play media content from a content item source (e.g. TUNEIN station, etc) on a SoundTouch device.",
Expand Down
22 changes: 22 additions & 0 deletions custom_components/soundtouchplus/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,28 @@
}
}
},
"musicservice_station_list": {
"name": "Get Music Service Station List",
"description": "Retrieves the list of your stored stations from the specified music service (e.g. PANDORA, etc).",
"fields": {
"entity_id": {
"name": "Entity ID",
"description": "Entity ID of the SoundTouch device that will query the specified music service."
},
"source": {
"name": "Source",
"description": "Music service source to navigate (e.g. 'PANDORA', etc); the value is case-sensitive, and should normally be UPPER case."
},
"source_account": {
"name": "Source Account",
"description": "Music service source account (e.g. the music service user-id). Default is none."
},
"sort_type": {
"name": "Sort Type",
"description": "Sort type used by the Music Service to sort the returned items by ('dateCreated', 'stationName'); the value is case-sensitive."
}
}
},
"play_contentitem": {
"name": "Play Content Item",
"description": "Play media content from a content item source (e.g. TUNEIN station, etc) on a SoundTouch device.",
Expand Down

0 comments on commit 774c838

Please sign in to comment.