157 lines
6.0 KiB
Markdown
157 lines
6.0 KiB
Markdown
# Sound Tower Controller
|
|
|
|
A small, unofficial desktop remote for Samsung Sound Tower speakers. Control
|
|
EQ, bass, lighting, RGB color, volume, mute, playback, and source selection
|
|
through Bluetooth Low Energy.
|
|
|
|
Verified interactively on one **Samsung MX-T40 with Windows**. Other models
|
|
and operating systems have not been verified. No firmware flashing, Samsung
|
|
account, or bundled vendor software is required.
|
|
|
|
## Run with uv
|
|
|
|
Use Windows Python for a Windows Bluetooth adapter. From WSL, invoke `uv.exe`
|
|
so Bluetooth runs on Windows rather than inside WSL.
|
|
|
|
```powershell
|
|
uv run soundtower
|
|
```
|
|
|
|
For WSL:
|
|
|
|
```bash
|
|
uv.exe run soundtower
|
|
```
|
|
|
|
1. Turn on Windows Bluetooth and power on the speaker. Close the phone's Sound
|
|
Tower app if it is holding the control connection.
|
|
2. Click **Scan**. The window stays responsive during the eight-second search.
|
|
3. Choose your speaker in the **Speaker** dropdown, then click **Connect**.
|
|
A single result is selected automatically when the field is empty; the app
|
|
never connects automatically. Addresses distinguish speakers with the same name.
|
|
4. Wait for **Speaker handshake complete**, then use the controls.
|
|
|
|
The MX-T40 can advertise without a name. The selector recognizes its known
|
|
model advertisement and shows **MX-T40 (model advertisement)** in that case.
|
|
Discovery of another Sound Tower model is not a compatibility guarantee.
|
|
|
|
`uv run python -m controller` remains supported, as does the earlier
|
|
`--with-requirements requirements.txt` launch command.
|
|
|
|
### Finding or entering the Bluetooth address manually
|
|
|
|
The selector includes the Bluetooth address after each speaker name. You can
|
|
also list candidate names and addresses from the terminal without opening Tk
|
|
or connecting to a speaker:
|
|
|
|
```powershell
|
|
uv run python -m controller.discovery
|
|
```
|
|
|
|
An address looks like `12:34:56:78:9A:BC`. Copy your speaker's actual address,
|
|
not that example, and either type it in the editable **Speaker** field or use:
|
|
|
|
```powershell
|
|
uv run soundtower --address YOUR_SPEAKER_MAC
|
|
```
|
|
|
|
Use the address observed in the BLE scan rather than assuming an audio-device
|
|
display name is an address. If no speaker appears, ensure Windows Bluetooth
|
|
and the speaker are on, close the phone app, and scan again. An already open
|
|
phone connection can affect advertising. Scanning lists advertisements only;
|
|
it does not send control commands or pair/remove devices.
|
|
|
|
Python 3.11 or newer is required; physical device testing used Windows Python
|
|
3.14. The interpreter needs Tcl/Tk. If the interpreter provided by uv lacks Tk,
|
|
use a Windows Python installation with Tk support, for example:
|
|
|
|
```powershell
|
|
uv run --python C:\Path\To\Python\python.exe soundtower --address YOUR_SPEAKER_MAC
|
|
```
|
|
|
|
## Controls
|
|
|
|
- EQ: Party, Standard, Hip-hop, EDM, Rock, Latin, House, Reggae.
|
|
- Bass boost, volume up/down, mute, play/pause, and audio source.
|
|
- Lighting: Off, Ambient, Party, Dance, Thunder, Star, Lover, Color.
|
|
- RGB color picker; lighting mode is queried after a color change.
|
|
- Readable activity log with optional raw packet display.
|
|
|
|
A command acknowledgment means the packet was received. A later status report
|
|
confirms the reported setting; the log distinguishes the two. Choosing an RGB
|
|
color switches the tested speaker to COLOR mode. A play/pause event does not
|
|
reveal the absolute playback state.
|
|
|
|
The source menu includes protocol options that may not exist on every model.
|
|
The tested MX-T40 reports Bluetooth, USB 1, AUX 1, and AUX 2.
|
|
|
|
## Audio versus control
|
|
|
|
This app opens the BLE remote-control connection. Windows establishes the
|
|
separate audio playback connection. Neither a BLE connection nor Windows'
|
|
word “Connected” guarantees an audio output is available.
|
|
|
|
If the speaker disappears from Windows' output list, disconnect/reconnect it
|
|
through Windows and select it as the sound output. Both connection orders
|
|
have worked in testing; no fixed startup order is established. Once playback
|
|
works, the BLE controller can operate alongside it.
|
|
|
|
The older RFCOMM/COM path is experimental and was unreliable on this MX-T40:
|
|
`--transport rfcomm` selects it. BLE is the default.
|
|
|
|
## Development
|
|
|
|
```bash
|
|
uv run --group dev python -m unittest discover -s tests -v
|
|
uv run --group dev ruff check controller tests scripts
|
|
uv run --group dev ruff format --check controller tests scripts
|
|
uv build
|
|
```
|
|
|
|
The first online `uv run` resolves dependencies and creates `uv.lock`; commit
|
|
that lockfile after resolving it for the project. A lockfile is not yet bundled
|
|
because dependency resolution was unavailable in the offline development shell.
|
|
|
|
The tests use captured packet fixtures and fake transports; they do not need
|
|
a speaker, Tk, or a display. They do not replace physical compatibility tests.
|
|
The optional GitHub Actions workflow runs headless tests on Windows/Linux and
|
|
Python 3.11/3.14. The same commands can be used in Gitea CI.
|
|
|
|
See [architecture](docs/ARCHITECTURE.md), [protocol](docs/PROTOCOL.md),
|
|
[feature research](docs/FEATURES.md), and [contributing](CONTRIBUTING.md).
|
|
|
|
## Diagnostics
|
|
|
|
List the MX-T40's advertised BLE/GATT endpoints without sending controls:
|
|
|
|
```powershell
|
|
uv run python -m controller.ble_probe
|
|
```
|
|
|
|
Experimental Windows RFCOMM discovery:
|
|
|
|
```powershell
|
|
uv run --extra diagnostics python -m controller.probe --channel 1
|
|
```
|
|
|
|
## Preparing a repository
|
|
|
|
This development folder also contains private research inputs. Export only the
|
|
controller, tests, and original documentation into a **new, empty directory**:
|
|
|
|
```bash
|
|
python scripts/export_project.py dist/soundtower-controller
|
|
```
|
|
|
|
The export uses an explicit allowlist. Firmware, APKs, extracted vendor files,
|
|
decompiled Java, environment files, and caches are excluded. Initialize Git in
|
|
that exported directory before adding a GitHub or Gitea remote. No remote is
|
|
configured and nothing is uploaded automatically.
|
|
|
|
## Project status
|
|
|
|
This is an independent interoperability project, not an official Samsung or
|
|
Qualcomm product. It contains original controller code and protocol notes,
|
|
not redistributed firmware or application code. A project license has not yet
|
|
been selected; no open-source license grant is currently declared.
|