2.9 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 |
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.
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.