├── .flake8 ├── LICENSE ├── README.md ├── bluetooth_scan.py └── pyproject.toml /.flake8: -------------------------------------------------------------------------------- 1 | [flake8] 2 | max-line-length = 132 3 | ignore = E501, W503, W504 4 | exclude = .git,__pycache__,.eggs/,doc/,docs/,build/,dist/,archive/ 5 | per-file-ignores = 6 | __init__.py:F401, F403 -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Michael Hirsch, Ph.D. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PyBlueZ Examples 2 | 3 | Example Bluetooth tasks using the Python 4 | [PyBluez](https://pybluez.github.io/) 5 | module. Tested using BlueZ 5 on: 6 | 7 | * Raspberry Pi 2 with CSR bluetooth 4.0 USB adapter 8 | * Raspberry Pi 3 / 4 (on-board Bluetooth) 9 | * laptop with Ubuntu 10 | * Windows (Bluetooth classic, non-BLE only) 11 | 12 | 13 | ## Linux 14 | 15 | For Ubuntu <= 18.04 we use system Python 2.7 for ease of library install. 16 | If you have Anaconda/Miniconda, you can alternatively use conda-forge libraries. 17 | 18 | 1. from Terminal: 19 | 20 | ```sh 21 | apt install python-pip python-bluez libbluetooth-dev libboost-python-dev libboost-thread-dev libglib2.0-dev bluez bluez-hcidump 22 | 23 | adduser lp $(whoami) 24 | ``` 25 | 2. setup Python code: 26 | 27 | ```sh 28 | python -m pip install -e . 29 | ``` 30 | 3. check that your Bluetooth devices are not blocked (should say "no"): 31 | 32 | ```sh 33 | rfkill list 34 | ``` 35 | 36 | 37 | ## Scan for bluetooth devices from Python 38 | 39 | ```sh 40 | python bluetooth_scan.py 41 | ``` 42 | 43 | If no Bluetooth devices found in the PyBluez device scan, try each of the following: 44 | 45 | ```sh 46 | hcitool scan 47 | ``` 48 | 49 | and: 50 | 51 | ```sh 52 | bluetoothctl 53 | 54 | scan on 55 | ``` 56 | 57 | If the second way finds devcies but not the first, you may have a chipset issue. 58 | I have noted this with Marvell hardware on Ubuntu 18.04. 59 | I did not look into a resolve for this, as I usually use other hardware. 60 | 61 | --- 62 | 63 | If you get error 64 | 65 | > OSError: No such device 66 | 67 | check that there is a Bluetooth adapter available: 68 | 69 | ```sh 70 | hciconfig dev 71 | ``` 72 | 73 | The bluetooth adapter may need to be enabled: 74 | 75 | ```sh 76 | hciconfig hci0 up 77 | ``` 78 | 79 | ## Non-Python Bluetooth examples 80 | 81 | These example use Bluez directly from Terminal (without Python) 82 | 83 | ### Bluetooth pairing 84 | 85 | using Bluez5 bluetoothctl agent: 86 | 87 | ```sh 88 | hciconfig hci0 up # enables bt on computer 89 | hcitool scan # gets UUID of devices in pairing mode 90 | hcitool dev # get BT adapter uuid 91 | 92 | bluetoothctl # starts interactive prompt 93 | scan on # scans for UUID of device (BT and BLE) in pairing mode 94 | pair uuid # where "uuid" is what you found with scan 95 | trust uuid 96 | connect uuid # after pairing, this is how you connect in the future 97 | ``` 98 | 99 | ## Notes 100 | 101 | If you get the error 102 | 103 | > Creating device failed: org.bluez.Error.AuthenticationRejected: 104 | > Authentication Rejected 105 | 106 | then edit `/etc/bin/bluez-simple-agent`, 107 | [changing](http://www.wolfteck.com/projects/raspi/iphone/) 108 | "KeyboardDisplay" to "DisplayYesNo" 109 | 110 | Also try: 111 | 112 | ```sh 113 | bluez-test-device trusted yes 114 | ``` 115 | 116 | If connected but lacking sound, try editing `~/.asoundrc`, 117 | [pasting in](https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=570468): 118 | 119 | ``` 120 | pcm.btspkr { 121 | type plug 122 | slave { 123 | pcm { 124 | type bluetooth 125 | device "AA:BB:CC:DD:EE:FF" 126 | profile "auto" 127 | } 128 | } 129 | hint { 130 | show on 131 | description "BT Speaker" 132 | } 133 | } 134 | ctl.btspkr { 135 | type bluetooth 136 | } 137 | 138 | pcm.btspkr_softvol 139 | { 140 | type softvol 141 | slave.pcm "btspkr" 142 | control.name "Bluetooth" 143 | control.card 0 144 | } 145 | 146 | # Using bluetooth as default : 147 | pcm.!default { 148 | type plug 149 | slave.pcm "btspkr_softvol" 150 | } 151 | ``` 152 | 153 | ## Bluetooth connect 154 | 155 | ```sh 156 | hcitool cc 157 | ``` 158 | 159 | I sometimes saw in Ubuntu that it disconnects after a second, maybe 160 | because system bluetooth menu is overriding with "off"? 161 | 162 | ## Errors 163 | 164 | > Cannot open shared library 165 | > /usr/lib/arm-linux-gnueabihf/alsa-lib/libasound_module_pcm_bluetooth.so 166 | 167 | ```sh 168 | apt install bluez-alsa 169 | ``` 170 | 171 | --- 172 | 173 | > bt_audio_service_open: connect() failed: Connection refused (111) 174 | 175 | 1. edit `/etc/bluetooth/audio.conf`, pasting in: 176 | 177 | ```ini 178 | [general] 179 | Enable=Sink,Source,Socket 180 | Disable=Media 181 | 182 | AutoConnect=true 183 | SCORouting=PCM 184 | ``` 185 | 2. then: 186 | 187 | ```sh 188 | service bluetooth restart 189 | ``` 190 | 191 | ## Set Bluetooth speaker as default audio device 192 | 193 | First test it works with: 194 | 195 | ```sh 196 | mpg321 -a bluetooth myfile.mp3 197 | ``` 198 | 199 | or: 200 | 201 | ```sh 202 | mplayer -ao alsa:device=bluetooth myfile.mp3 203 | ``` 204 | 205 | Then, list your audio ALSA devices with: 206 | 207 | ```sh 208 | aplay -L 209 | ``` 210 | 211 | and you can use: 212 | 213 | ```sh 214 | alsamixer 215 | ``` 216 | 217 | ## References 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | -------------------------------------------------------------------------------- /bluetooth_scan.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """ 3 | Bluetooth device scanning/discovery 4 | 5 | http://blog.kevindoran.co/bluetooth-programming-with-python-3/ 6 | https://github.com/pybluez/pybluez 7 | """ 8 | import bluetooth as bt 9 | 10 | try: 11 | from bluetooth.ble import DiscoveryService 12 | except ImportError: 13 | DiscoveryService = None 14 | 15 | 16 | def bluetooth_classic_scan(timeout=10): 17 | """ 18 | This scan finds ONLY Bluetooth classic (non-BLE) devices in *pairing mode* 19 | """ 20 | return bt.discover_devices(duration=scansec, flush_cache=True, lookup_names=True) 21 | 22 | 23 | def bluetooth_low_energy_scan(timeout=10): 24 | """ 25 | currently Linux only 26 | """ 27 | if DiscoveryService is None: 28 | return None 29 | 30 | svc = DiscoveryService() 31 | return svc.discover(timeout) 32 | 33 | 34 | if __name__ == "__main__": 35 | scansec = 5 # how long to scan for (seconds) 36 | 37 | dev_classic = bluetooth_classic_scan(scansec) 38 | if dev_classic: 39 | for d in dev_classic: 40 | print(d) 41 | 42 | dev_ble = bluetooth_low_energy_scan(scansec) 43 | if dev_ble: 44 | for u, n in dev_ble.items(): 45 | print(u, n) 46 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = ["setuptools>=61.0.0", "wheel"] 3 | build-backend = "setuptools.build_meta" 4 | 5 | [project] 6 | requires-python = ">=3.7" 7 | dependencies = ["pybluez"] 8 | 9 | [tool.black] 10 | line-length = 100 11 | 12 | [tool.mypy] 13 | files = ["."] 14 | 15 | ignore_missing_imports = true 16 | strict_optional = false 17 | show_column_numbers = true 18 | --------------------------------------------------------------------------------