Bluetooth Scanner Example¶
An example showing how to locate Bluetooth devices.
"""PySide6 port of the bluetooth/btscanner example from Qt v6.x"""
import sys
from PySide6.QtCore import Qt
from PySide6.QtWidgets import QApplication, QWidget
from device import DeviceDiscoveryDialog
if __name__ == '__main__':
app = QApplication(sys.argv)
d = DeviceDiscoveryDialog()
d.exec()
sys.exit(0)
from PySide6.QtCore import QPoint, Qt, Slot
from PySide6.QtGui import QColor
from PySide6.QtWidgets import QDialog, QListWidgetItem, QListWidget, QMenu
from PySide6.QtBluetooth import (QBluetoothAddress, QBluetoothDeviceDiscoveryAgent,
QBluetoothDeviceInfo, QBluetoothLocalDevice)
from ui_device import Ui_DeviceDiscovery
from service import ServiceDiscoveryDialog
class DeviceDiscoveryDialog(QDialog):
def __init__(self, parent=None):
super().__init__(parent)
self._local_device = QBluetoothLocalDevice()
self._ui = Ui_DeviceDiscovery()
self._ui.setupUi(self)
# In case of multiple Bluetooth adapters it is possible to set adapter
# which will be used. Example code:
#
# address = QBluetoothAddress("XX:XX:XX:XX:XX:XX")
# discoveryAgent = QBluetoothDeviceDiscoveryAgent(address)
self._discovery_agent = QBluetoothDeviceDiscoveryAgent()
self._ui.scan.clicked.connect(self.start_scan)
self._discovery_agent.deviceDiscovered.connect(self.add_device)
self._discovery_agent.finished.connect(self.scan_finished)
self._ui.list.itemActivated.connect(self.item_activated)
self._local_device.hostModeStateChanged.connect(self.host_mode_state_changed)
self.host_mode_state_changed(self._local_device.hostMode())
# add context menu for devices to be able to pair device
self._ui.list.setContextMenuPolicy(Qt.CustomContextMenu)
self._ui.list.customContextMenuRequested.connect(self.display_pairing_menu)
self._local_device.pairingFinished.connect(self.pairing_done)
@Slot(QBluetoothDeviceInfo)
def add_device(self, info):
a = info.address().toString()
label = f"{a} {info.name()}"
items = self._ui.list.findItems(label, Qt.MatchExactly)
if not items:
item = QListWidgetItem(label)
pairing_status = self._local_device.pairingStatus(info.address())
if (pairing_status == QBluetoothLocalDevice.Paired
or pairing_status == QBluetoothLocalDevice.AuthorizedPaired):
item.setForeground(QColor(Qt.green))
else:
item.setForeground(QColor(Qt.black))
self._ui.list.addItem(item)
@Slot()
def start_scan(self):
self._discovery_agent.start()
self._ui.scan.setEnabled(False)
@Slot()
def scan_finished(self):
self._ui.scan.setEnabled(True)
@Slot(QListWidgetItem)
def item_activated(self, item):
text = item.text()
index = text.find(' ')
if index == -1:
return
address = QBluetoothAddress(text[0:index])
name = text[index + 1:]
d = ServiceDiscoveryDialog(name, address)
d.exec()
@Slot(bool)
def on_discoverable_clicked(self, clicked):
if clicked:
self._local_device.setHostMode(QBluetoothLocalDevice.HostDiscoverable)
else:
self._local_device.setHostMode(QBluetoothLocalDevice.HostConnectable)
@Slot(bool)
def on_power_clicked(self, clicked):
if clicked:
self._local_device.powerOn()
else:
self._local_device.setHostMode(QBluetoothLocalDevice.HostPoweredOff)
@Slot(QBluetoothLocalDevice.HostMode)
def host_mode_state_changed(self, mode):
self._ui.power.setChecked(mode != QBluetoothLocalDevice.HostPoweredOff)
self._ui.discoverable.setChecked(mode == QBluetoothLocalDevice.HostDiscoverable)
on = mode != QBluetoothLocalDevice.HostPoweredOff
self._ui.scan.setEnabled(on)
self._ui.discoverable.setEnabled(on)
@Slot(QPoint)
def display_pairing_menu(self, pos):
if self._ui.list.count() == 0:
return
menu = QMenu(self)
pair_action = menu.addAction("Pair")
remove_pair_action = menu.addAction("Remove Pairing")
chosen_action = menu.exec(self._ui.list.viewport().mapToGlobal(pos))
current_item = self._ui.list.currentItem()
text = current_item.text()
index = text.find(' ')
if index == -1:
return
address = QBluetoothAddress(text[0:index])
if chosen_action == pair_action:
self._local_device.requestPairing(address, QBluetoothLocalDevice.Paired)
elif chosen_action == remove_pair_action:
self._local_device.requestPairing(address, QBluetoothLocalDevice.Unpaired)
@Slot(QBluetoothAddress, QBluetoothLocalDevice.Pairing)
def pairing_done(self, address, pairing):
items = self._ui.list.findItems(address.toString(), Qt.MatchContains)
color = QColor(Qt.red)
if pairing == QBluetoothLocalDevice.Paired or pairing == QBluetoothLocalDevice.AuthorizedPaired:
color = QColor(Qt.green)
for item in items:
item.setForeground(color)
from PySide6.QtCore import Qt, Slot
from PySide6.QtWidgets import QDialog
from PySide6.QtBluetooth import (QBluetoothAddress, QBluetoothServiceInfo,
QBluetoothServiceDiscoveryAgent, QBluetoothLocalDevice)
from ui_service import Ui_ServiceDiscovery
class ServiceDiscoveryDialog(QDialog):
def __init__(self, name, address, parent=None):
super().__init__(parent)
self._ui = Ui_ServiceDiscovery()
self._ui.setupUi(self)
# Using default Bluetooth adapter
local_device = QBluetoothLocalDevice()
adapter_address = QBluetoothAddress(local_device.address())
# In case of multiple Bluetooth adapters it is possible to
# set which adapter will be used by providing MAC Address.
# Example code:
#
# adapterAddress = QBluetoothAddress("XX:XX:XX:XX:XX:XX")
# discoveryAgent = QBluetoothServiceDiscoveryAgent(adapterAddress)
self._discovery_agent = QBluetoothServiceDiscoveryAgent(adapter_address)
self._discovery_agent.setRemoteAddress(address)
self.setWindowTitle(name)
self._discovery_agent.serviceDiscovered.connect(self.add_service)
self._discovery_agent.finished.connect(self._ui.status.hide)
self._discovery_agent.start()
@Slot(QBluetoothServiceInfo)
def add_service(self, info):
line = info.serviceName()
if not line:
return
if info.serviceDescription():
line += "\n\t" + info.serviceDescription()
if info.serviceProvider():
line += "\n\t" + info.serviceProvider()
self._ui.list.addItem(line)
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>DeviceDiscovery</class>
<widget class="QDialog" name="DeviceDiscovery">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>411</height>
</rect>
</property>
<property name="windowTitle">
<string>Bluetooth Scanner</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QListWidget" name="list"/>
</item>
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Local Device</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QCheckBox" name="power">
<property name="text">
<string>Bluetooth Powered On</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="discoverable">
<property name="text">
<string>Discoverable</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QPushButton" name="scan">
<property name="text">
<string>Scan</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="clear">
<property name="text">
<string>Clear</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="quit">
<property name="text">
<string>Quit</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>quit</sender>
<signal>clicked()</signal>
<receiver>DeviceDiscovery</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>323</x>
<y>275</y>
</hint>
<hint type="destinationlabel">
<x>396</x>
<y>268</y>
</hint>
</hints>
</connection>
<connection>
<sender>clear</sender>
<signal>clicked()</signal>
<receiver>list</receiver>
<slot>clear()</slot>
<hints>
<hint type="sourcelabel">
<x>188</x>
<y>276</y>
</hint>
<hint type="destinationlabel">
<x>209</x>
<y>172</y>
</hint>
</hints>
</connection>
</connections>
</ui>
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ServiceDiscovery</class>
<widget class="QDialog" name="ServiceDiscovery">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>539</width>
<height>486</height>
</rect>
</property>
<property name="windowTitle">
<string>Available Services</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QListWidget" name="list"/>
</item>
<item>
<widget class="QLabel" name="status">
<property name="text">
<string>Querying...</string>
</property>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="standardButtons">
<set>QDialogButtonBox::Close</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>ServiceDiscovery</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>396</x>
<y>457</y>
</hint>
<hint type="destinationlabel">
<x>535</x>
<y>443</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>ServiceDiscovery</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>339</x>
<y>464</y>
</hint>
<hint type="destinationlabel">
<x>535</x>
<y>368</y>
</hint>
</hints>
</connection>
</connections>
</ui>
© 2022 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.