# Bose-SoundTouch-API (boseapi)




This small project/repository contains general information about how to analyze the firmware images provided by _`BOSE`_ and also implements commands to interact with these devices. The API and some basic usage examples are provided in the [api-documentation](https://bose-soundtouch-api.readthedocs.io).
## Installation
This module can be easily installed via pip:
```bash
$ python3 -m pip install boseapi
```
## Usage
```python
from boseapi.all import *
device = new_device('127.0.0.1')
client = SoundTouchClient(device, errors='ignore')
# fetch device's capabilities
capabilities = client.capabilities()
if capabilities.wsapiproxy:
# Create and use a WebSocket client
ws_client = BoseWebSocket(device)
# Add a listener on an updated volume
ws_client.add_listener(nodes.volumeupdated, lambda xmlelement: print(xmlelement.tag))
ws_client.start_notification()
# Get the current volume and appply a new value to it (0..100).
volume = client.volume()
# client.set_volume(7)
# client.set_volume(volume.actual_vol + 1)
# has the same effect as
client.volume_up()
# If media is currently played by the device:
status = client.status()
if status.play_status != 'PLAY_STATE':
# Play own media
item = ContentItem(src=Source.INTERNET_RADIO, location='4712')
client.play(item)
# Load and select presets
presets = client.listpresets()
if len(presets) > 0:
preset = presets[0]
client.select_preset(preset)
# Multiroom functionality
current_zone = client.zone_status()
if current_zone.masterid == None:
zone = Zone(device_id=device.device_id, ip=device.host)
# Add different zone slaves (it is recommended to create new devices
# befor adding a zone slave.
device2 = boseapi.new_device('127.0.0.2')
slave = ZoneSlave(device_id=device2.device_id, ip_address=device2.host)
zone.append(slave)
# Create zone/ Add slaves/ Remove slaves
client.create_zone(zone)
client.remove_zone_slave([slave])
client.add_zone_slave([slave])
# List all available UPnP MediaServers
media_servers = client.media_servers()
if len(media_servers) > 0:
for server in media_servers:
print(server)
# List all available sources
sources = client.listsources()
if len(sources) > 0:
# Get specific source items with the source name
source_item = sources['QPLAY']
# or the index position
source_item2 = sources[0]
# Select different input sources
client.select_source(Source.BLUETOOTH)
if source_item.status == 'READY':
client.select_source(source_item.source)
# make sure the node is available be fore fetching data
if 'GET' in client.options(nodes.bass):
# manually fetch or set data
message = client.get(nodes.bass)
bass = Bass(message.response)
client.put(nodes.bass, '<bass>0</bass>')
```
## Overview
---
Starting off with the used device and app to get the information used to write the code for this repository.
> `Bose SoundTouch 300` and the `SoundTouch` app by BOSE
While capturing traffic of the BOSE device the following URL was requested when searching for a sofware update:
> https://downloads.bose.com/updates/soundtouch
The request is forwarded to another backend which contains a XML-Document named `index.xml`. This file contains information about the locations of all available firmware upgrades. Since the device used here needs the `SoundTouch 30` firmware, the following link is used.
> https://downloads.bose.com/ced/soundtouch/mr4_cdb9ab51/Update_ti_27.0.3.46298.4608935.scm.stu
After downloading, a quick review with binwalk on the file:
```console
$ binwalk Update_ti_27.0.3.46298.4608935.scm.stu
DECIMAL HEXADECIMAL DESCRIPTION
--------------------------------------------------------------------------------
312 0x138 ELF, 32-bit LSB executable, ARM, version 1 (SYSV)
[...]
13932404 0xD49774 UBI erase count header, version: 1, EC: 0x0, VID header offset: 0x800, data offset: 0x1000
[...]
```
The only interesting line in the binwalk output contains information about an UBI image header. So, extract that file and decompress it with `ubidump`:
```console
$ ubidump -s . D49774.ubi
```
This command creates a folder in the current directory where all the contents of this UBI document are stored. Files that contain information usable for creating this API are located in the following directory: `rootfs/opt/Bose/etc/`.
There are two files that configure operations that can be requested/ executed on the webserver (port `8090`). All operations contained in:
```bash
rootfs/opt/Bose/etc/HandCraftedWebServer-SoundTouch.xml
# and
rootfs/opt/Bose/etc/WebServer-SoundTouch.xml
```
were implemented in this small library.
---
## Contributing
Contributions are what make the open source community such an amazing place to learn, inspire, and create. Any contributions you make are **greatly appreciated**.
If you have a suggestion that would make this better, please fork the repo and create a pull request. You can also simply open an issue with the tag "enhancement".
1. Fork the Project
2. Create your Feature Branch (`git checkout -b feature/AmazingFeature`)
3. Commit your Changes (`git commit -m 'Add some AmazingFeature'`)
4. Push to the Branch (`git push origin feature/AmazingFeature`)
5. Open a Pull Request
<!-- LICENSE -->
---
## License
Distributed under the MIT License. See `MIT.txt` for more information.