196 lines
7.5 KiB
Markdown
196 lines
7.5 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
|
|
```
|
|
|
|
## Build a Windows executable
|
|
|
|
Build using **Windows PowerShell and Windows Python**, not a Linux Python
|
|
interpreter in WSL. [PyInstaller builds for the operating system it runs on](https://pyinstaller.org/en/stable/).
|
|
|
|
```powershell
|
|
git clone https://git.ldlda.com/lda/soundtower-controller.git
|
|
cd soundtower-controller
|
|
uv run --locked --python 3.14 --group bundle python scripts/build_exe.py
|
|
```
|
|
|
|
If you already cloned the repository, run `git pull --ff-only` there instead
|
|
of cloning again. If uv's selected interpreter lacks Tcl/Tk, use a Windows
|
|
Python installation with Tk via `--python C:\Path\To\Python\python.exe`.
|
|
|
|
The application is created at:
|
|
|
|
```text
|
|
dist\SoundTowerController\SoundTowerController.exe
|
|
```
|
|
|
|
Double-click it and use Scan → choose speaker → Connect. Keep the **entire
|
|
SoundTowerController folder**, including `_internal`, together when copying it
|
|
to another computer. The recipient does not need uv or Python installed.
|
|
|
|
For a single-file executable instead:
|
|
|
|
```powershell
|
|
uv run --locked --python 3.14 --group bundle python scripts/build_exe.py --onefile
|
|
```
|
|
|
|
That creates `dist\SoundTowerController.exe`; it extracts dependencies when
|
|
launched. If startup fails, rebuild with `--console` to see the error. No code
|
|
signing certificate is configured, so the build is an unsigned executable.
|
|
The build script's arguments are tested; a real Windows executable build still
|
|
requires validation on Windows.
|
|
|
|
## 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 committed `uv.lock` pins runtime, development, and Windows build dependencies.
|
|
Use `uv lock` when intentionally changing dependencies; the executable build
|
|
examples use `--locked` so an out-of-date lockfile fails rather than changing
|
|
silently.
|
|
|
|
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
|
|
|
|
If working from a mixed firmware-research workspace, export only the controller,
|
|
tests, and original documentation into a **new, empty directory**. A normal
|
|
clone of this repository already contains only the publishable source:
|
|
|
|
```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.
|