|
1 | 1 | # Universal Bluetooth SDK |
2 | 2 |
|
3 | | -Cross-language, multi-service toolkit for building Bluetooth solutions (RFCOMM |
4 | | -today, BLE-ready tomorrow). The Python SDK is production-ready; other folders |
5 | | -are scaffolding for future Go/Rust SDKs, microservices, and CLI tooling. |
| 3 | +Cross-language, cross-platform toolkit for building Bluetooth solutions. The |
| 4 | +control plane is a single long-lived daemon (`ubtd`) that owns every radio |
| 5 | +session; everything else — the typed CLI, the AI planner, the MCP server, the |
| 6 | +language SDKs — talks to it through one versioned wire format. |
| 7 | + |
| 8 | +``` |
| 9 | +ubtctl ──┐ ┌── BlueZ (Linux) |
| 10 | +ubtctl ask│ ──UDS── ubtd ─── TransportDriver ────────┤ |
| 11 | +ubtctl mcp│ │ ├── CoreBluetooth (TODO) |
| 12 | +MCP client┘ └── audit / policy / sessions └── WinRT (TODO) |
| 13 | + │ |
| 14 | + └── Python / Go / Rust SDKs (same protocol) |
| 15 | +``` |
| 16 | + |
| 17 | +## What's working today |
| 18 | + |
| 19 | +- **`ubtd`** — Go daemon, Unix-socket control plane, pluggable transport |
| 20 | + drivers, structured slog, signal-driven shutdown. |
| 21 | + - `--driver stub` — in-memory reference driver (any host). |
| 22 | + - `--driver linuxrfcomm` — BlueZ-backed RFCOMM via the kernel's |
| 23 | + `AF_BLUETOOTH` socket; `Discover` enumerates known peers via |
| 24 | + `bluetoothctl devices`. |
| 25 | +- **`ubtctl`** — Go CLI. One binary, several front-ends: |
| 26 | + - Typed verbs: `ping`, `version`, `status`, `capabilities`, |
| 27 | + `discover`, `send`. |
| 28 | + - **AI planner**: `ubtctl ask "<goal>"` runs Claude Opus 4.7 with |
| 29 | + adaptive thinking against a tool registry that is 1:1 with the |
| 30 | + daemon's RPC surface. |
| 31 | + - **MCP server**: `ubtctl mcp` exposes the same tool registry over |
| 32 | + JSON-RPC 2.0 on stdio, so any MCP-aware editor or agent (Claude |
| 33 | + Desktop, Cursor, Zed, …) can drive ubtd directly. |
| 34 | + - **Plan record/replay**: `ubtctl ask --save plan.json …` captures |
| 35 | + every tool call; `ubtctl plan show / run` replay it later without |
| 36 | + going back to the LLM. Mutating steps are gated behind `--yes`. |
| 37 | +- **Python SDK (`sdk/python`)** — production-ready PyBluez SDK kept around |
| 38 | + as the reference implementation and as a path the daemon can shell out to |
| 39 | + on hosts where a native driver isn't ready yet. |
| 40 | +- **Common contract (`common/protocol/`)** — `v1.proto` IDL (future |
| 41 | + gRPC) plus `framing.md` describing the v1 wire (length-prefixed JSON |
| 42 | + over UDS). |
6 | 43 |
|
7 | 44 | ## Repository layout |
8 | 45 |
|
9 | 46 | ``` |
10 | 47 | . |
| 48 | +├── cli/ |
| 49 | +│ ├── ubtd/ # Go daemon (UDS server, dispatcher) |
| 50 | +│ └── ubtctl/ # Go CLI (typed verbs, ai planner, mcp server) |
| 51 | +│ ├── ai/ # Claude tool runner + plan record/replay |
| 52 | +│ ├── client/ # daemon client (length-prefixed JSON codec) |
| 53 | +│ ├── commands/ # subcommand registry (ping/status/.../ask/mcp/plan) |
| 54 | +│ ├── mcp/ # JSON-RPC 2.0 MCP server (stdio) |
| 55 | +│ └── tools/ # neutral Spec/Registry shared by ai + mcp |
11 | 56 | ├── sdk/ |
12 | | -│ ├── python/ # fully implemented PyBluez SDK |
13 | | -│ ├── go/ # placeholder for Go SDK |
14 | | -│ └── rust/ # placeholder for Rust SDK |
| 57 | +│ ├── go/pkg/ |
| 58 | +│ │ ├── protocol/ # wire envelope + codec |
| 59 | +│ │ ├── sockaddr/ # default socket location |
| 60 | +│ │ └── transport/ # Driver port + Registry |
| 61 | +│ │ ├── stub/ # in-memory reference driver |
| 62 | +│ │ └── linuxrfcomm/ # BlueZ-backed RFCOMM (Linux only) |
| 63 | +│ ├── python/ # production-ready PyBluez SDK |
| 64 | +│ └── rust/ # planned |
15 | 65 | ├── microservices/ |
16 | | -│ ├── grpc-server/ # future gRPC control-plane |
17 | | -│ └── rest-server/ # future REST façade |
18 | | -├── cli/ |
19 | | -│ └── ubtctl/ # future CLI tool |
20 | | -├── examples/ # scenario-specific samples |
21 | | -├── common/ # shared protocols & schemas |
22 | | -└── docs/ # architecture & guides |
| 66 | +│ ├── grpc-server/ # planned (REST/gRPC façade for remote callers) |
| 67 | +│ └── rest-server/ |
| 68 | +├── common/ |
| 69 | +│ ├── protocol/ # v1.proto + framing.md |
| 70 | +│ └── message-schema/ |
| 71 | +├── examples/ # scenario samples (chat, sensor stream, file xfer) |
| 72 | +└── docs/ |
23 | 73 | ``` |
24 | 74 |
|
25 | | -## Python SDK (sdk/python) |
26 | | - |
27 | | -### Prerequisites |
28 | | - |
29 | | -PyBluez + BlueZ on Linux (tested on Raspberry Pi OS / Ubuntu). Install via the |
30 | | -helper script: |
| 75 | +## Quick start (Go) |
31 | 76 |
|
32 | 77 | ```bash |
33 | | -cd sdk/python |
34 | | -sudo ./scripts/install_dependencies.sh |
35 | | -``` |
36 | | - |
37 | | -Or install packages manually (Debian/Ubuntu): |
38 | | - |
39 | | -``` |
40 | | -sudo apt-get install python3 python3-dev python3-pip ipython3 |
41 | | -sudo apt-get install bluetooth libbluetooth-dev bluez bluez-tools blueman |
42 | | -sudo python3 -m pip install pybluez |
43 | | -``` |
44 | | - |
45 | | -### Usage |
| 78 | +go build -o bin/ubtd ./cli/ubtd |
| 79 | +go build -o bin/ubtctl ./cli/ubtctl |
46 | 80 |
|
47 | | -Run commands from `sdk/python` (or set `PYTHONPATH` accordingly). |
| 81 | +# 1. Start the daemon. Use `stub` for a hardware-free dev loop; |
| 82 | +# on Linux, switch to linuxrfcomm to talk to real radios. |
| 83 | +./bin/ubtd --socket /tmp/ubtd.sock --driver stub & |
48 | 84 |
|
49 | | -1. **Start the server (e.g., on Raspberry Pi)** |
50 | | - ```bash |
51 | | - cd sdk/python |
52 | | - sudo python3 run_server.py |
53 | | - ``` |
54 | | - - Customize behaviour via `bluetooth_service/config.py` (`ServerSettings`). |
55 | | - - Use `LOG_CFG=/path/to/logger.json` to override the default logger config. |
| 85 | +# 2. Drive it from the typed CLI. |
| 86 | +UBTD_SOCKET=/tmp/ubtd.sock ./bin/ubtctl status |
| 87 | +UBTD_SOCKET=/tmp/ubtd.sock ./bin/ubtctl discover --scan-timeout 3 |
56 | 88 |
|
57 | | -2. **Send data from the client** |
58 | | - ```bash |
59 | | - cd sdk/python |
60 | | - sudo python3 run_client.py |
61 | | - ``` |
62 | | - - Update `bluetooth_service/client_config.py` for UUID, discovery retries, |
63 | | - payload source, etc. |
64 | | - - Default payload is `text.json`; inject your own `DataSource` for custom |
65 | | - payloads. |
| 89 | +# 3. Or drive it from natural language (requires ANTHROPIC_API_KEY). |
| 90 | +ANTHROPIC_API_KEY=... ./bin/ubtctl ask \ |
| 91 | + --save /tmp/last.plan.json \ |
| 92 | + "show me the daemon status and list any nearby devices" |
66 | 93 |
|
67 | | -3. **Run unit tests (no Bluetooth hardware required)** |
68 | | - ```bash |
69 | | - cd sdk/python |
70 | | - python3 -m pip install pytest |
71 | | - pytest tests/ |
72 | | - ``` |
73 | | - Tests use socket stubs to stay deterministic on any host. |
74 | | - |
75 | | -## Platform setup tips |
76 | | - |
77 | | -Make your Raspberry Pi discoverable: |
78 | | - |
79 | | -``` |
80 | | -sudo hciconfig hci0 piscan |
81 | | -``` |
82 | | - |
83 | | -Run the classic inquiry example (optional): |
| 94 | +# 4. Replay the captured plan against the same daemon — no LLM, no spend. |
| 95 | +UBTD_SOCKET=/tmp/ubtd.sock ./bin/ubtctl plan show /tmp/last.plan.json |
| 96 | +UBTD_SOCKET=/tmp/ubtd.sock ./bin/ubtctl plan run /tmp/last.plan.json |
84 | 97 |
|
| 98 | +# 5. Or expose the same tool registry over MCP for editors / external agents. |
| 99 | +./bin/ubtctl mcp --socket /tmp/ubtd.sock # speaks JSON-RPC on stdio |
85 | 100 | ``` |
86 | | -sudo python inquiry.py |
87 | | -``` |
88 | | - |
89 | | -## Known Issues |
90 | | - |
91 | | -``` |
92 | | -Traceback (most recent call last): |
93 | | - File "/usr/share/doc/python-bluez/examples/simple/rfcomm-server.py", line 20, in <module> |
94 | | - profiles = [ SERIAL_PORT_PROFILE ], |
95 | | - File "/usr/lib/python2.7/dist-packages/bluetooth/bluez.py", line 176, in advertise_service |
96 | | - raise BluetoothError (str (e)) |
97 | | -bluetooth.btcommon.BluetoothError: (2, 'No such file or directory') |
98 | | -``` |
99 | | - |
100 | | -## Possible fixes |
101 | 101 |
|
102 | | -Make sure you are using sudo when running the python script |
103 | | -Make sure you have the serial profile loaded. How to enable the serial profile. |
| 102 | +For per-command flags and MCP client config, see |
| 103 | +[`cli/ubtctl/README.md`](cli/ubtctl/README.md). |
104 | 104 |
|
105 | | -As it turns out, the culprit is bluetoothd, the Bluetooth daemon. Using SDP with bluetoothd requires deprecated features for some silly reason, so to fix this, the daemon must be started in compatibility mode with bluetoothd -C (or bluetooth --compat). |
106 | | - |
107 | | -You need to run the Bluetooth daemon in 'compatibility' mode. Edit /lib/systemd/system/bluetooth.service and add '-C' after 'bluetoothd'. Reboot. |
108 | | - |
109 | | -``` |
110 | | -sudo sdptool add SP |
111 | | -``` |
112 | | - |
113 | | -Or |
114 | | - |
115 | | -Find location of bluetooth.service by: |
116 | | - |
117 | | -``` |
118 | | -systemctl status bluetooth.service |
119 | | -``` |
120 | | -Then edit bluetooth.service and look for ExecStart=/usr/libexec/bluetooth/bluetoothd |
121 | | -Append --compat at the end of this line, save, and then run |
122 | | - |
123 | | -``` |
124 | | -service bluetooth start |
125 | | -``` |
126 | | - |
127 | | -If all goes well, you should be able to successfully run |
128 | | - |
129 | | -``` |
130 | | -sudo sdptool browse local |
131 | | -``` |
| 105 | +## Python SDK (sdk/python) |
132 | 106 |
|
133 | | -Finally, reset the adapter: |
| 107 | +Production-ready PyBluez RFCOMM client/server. Tested on Raspberry Pi OS and |
| 108 | +Ubuntu. Detailed setup, troubleshooting, and the full PyBluez fix-up notes |
| 109 | +live in [`sdk/python/README.md`](sdk/python/README.md). |
134 | 110 |
|
135 | | -``` |
136 | | -sudo hciconfig -a hci0 reset |
| 111 | +```bash |
| 112 | +cd sdk/python |
| 113 | +sudo ./scripts/install_dependencies.sh |
| 114 | +sudo python3 run_server.py |
| 115 | +sudo python3 run_client.py |
137 | 116 | ``` |
138 | 117 |
|
139 | 118 | ## Roadmap |
140 | 119 |
|
141 | | -- Flesh out Go/Rust SDKs under `sdk/`. |
142 | | -- Build microservices (gRPC + REST) that wrap the SDK for remote control. |
143 | | -- Ship `ubtctl` CLI for device management. |
144 | | -- Provide ready-to-run examples (chat, sensor stream, file transfer). |
| 120 | +- **CoreBluetooth (macOS) and WinRT (Windows) drivers** — same `Driver` |
| 121 | + interface as `linuxrfcomm`; the daemon already advertises the capability |
| 122 | + matrix at runtime. |
| 123 | +- **`Listen` / `Reply` RPCs** — bidirectional RFCOMM sessions for chat / |
| 124 | + long-lived data streams (foundation for an offline Bluetooth chat app |
| 125 | + with a local-AI assist). |
| 126 | +- **gRPC v2 wire** — generated from `common/protocol/v1.proto`, |
| 127 | + alongside the JSON-over-UDS v1 wire during migration. |
| 128 | +- **Native Go and Rust SDKs** — same `protocol` package the daemon and CLI |
| 129 | + already use. |
| 130 | +- **`microservices/{grpc,rest}-server`** — remote control planes that |
| 131 | + re-export the daemon surface. |
145 | 132 |
|
146 | | -<!-- CONTRIBUTING --> |
147 | 133 | ## Contributing |
148 | 134 |
|
149 | | -Contributions are what make the open source community such an amazing place to be learn, inspire, and create. Any contributions you make are **greatly appreciated**. Please read the [contribution guidelines](https://github.com/sraodev/super-opensource-cheat-sheets/blob/master/contributing.md) first. |
150 | | - |
151 | | -## Reference |
152 | | - |
153 | | -[Bluetooth Programming with Python 3](http://blog.kevindoran.co/bluetooth-programming-with-python-3) |
154 | | - |
155 | | -[Bluetooth programming with Python - PyBluez](https://people.csail.mit.edu/albert/bluez-intro/x232.html) |
| 135 | +Issues and PRs welcome. Read the |
| 136 | +[contribution guidelines](https://github.com/sraodev/super-opensource-cheat-sheets/blob/master/contributing.md) |
| 137 | +first. |
156 | 138 |
|
157 | | -[Bluetooth for Programmers](http://people.csail.mit.edu/rudolph/Teaching/Articles/PartOfBTBook.pdf) |
| 139 | +## References |
158 | 140 |
|
159 | | -[Bluetooth Python extension module](https://github.com/karulis/pybluez) |
| 141 | +- [Bluetooth Programming with Python 3](http://blog.kevindoran.co/bluetooth-programming-with-python-3) |
| 142 | +- [Bluetooth Programming with Python — PyBluez](https://people.csail.mit.edu/albert/bluez-intro/x232.html) |
| 143 | +- [Bluetooth for Programmers](http://people.csail.mit.edu/rudolph/Teaching/Articles/PartOfBTBook.pdf) |
| 144 | +- [PyBluez](https://github.com/karulis/pybluez) |
| 145 | +- [Model Context Protocol](https://modelcontextprotocol.io/) |
0 commit comments