Files

3.3 KiB

Architecture

The protocol module has no Bluetooth or GUI dependencies. Tk exists only in controller/gui.py, which cli.py imports after parsing arguments. Importing the package or running --help does not load Tk or Bleak.

Module Responsibility
protocol.py Packet encoding, stream framing, observed checksum variants
commands.py Semantic command builders; no packet layout in Tk callbacks
session.py Handshake, outgoing sequence numbers, connection readiness
messages.py English command/reply descriptions and bounded activity history
worker.py Thread lifecycle and event/command queues
ble_link.py Bleak connection, notifications, characteristic writes
link.py, transport.py Experimental RFCOMM and serial adapters
gui.py Tk controls and event rendering
discovery.py Read-only BLE discovery, unnamed model matching, and selectable labels
cli.py, __main__.py Installed command and backwards-compatible module entry
ble_probe.py, probe.py Endpoint diagnostics
windows_bluetooth.py Experimental RFCOMM initialization

Session interface

Create one Session per connection. Write session.start() to begin. Pass received chunks to session.receive(chunk) and write every returned outgoing packet. Update.frames carries decoded packets; became_ready is emitted once when the speaker acknowledges the link-complete request. Use session.command(payload) for subsequent outgoing packets.

Both transports cross this same seam. The session owns framing and the state machine, so fixes do not need to be repeated in separate Bluetooth loops.

A transport connection, a GATT write response, a Samsung packet acknowledgment, and a speaker state report are distinct events. Only the link-complete ACK makes the session ready. Speaker notifications have an independent sequence counter and cannot substitute for that ACK.

Threads and ownership

Tk runs on the main thread. Each connection worker owns its transport. BLE's async event loop lives entirely within the worker thread. The GUI submits payloads through a bounded command queue and consumes events through another queue; workers never call Tk methods.

Discovery uses a separate bounded-duration worker and the same event queue. It returns plain speaker records without opening a GATT connection. Tk maps a selected label to its address; manual addresses remain supported. Scanning is disabled while a connection is active so scans do not compete with BLE traffic.

BLE notifications enter a bounded async queue and can contain partial or combined packets. The decoder retains framing state between notifications. Queue overflow terminates the connection rather than silently losing framing.

Writes are spaced and never automatically retried. Retrying a volume or mute key could perform the action twice. The GUI enables controls only after the protocol handshake and disables them on connection closure.

Testing

Protocol tests use captured byte fixtures independently of the outgoing encoder. Session tests cover split replies, duplicate replies, and ACK matching. Transport tests verify subscription order, write mode, disconnects, resource cleanup, and readable error phases. Presentation tests verify the difference between acknowledgment and a reported state. No test opens physical Bluetooth.