Bluetooth Scanner Example¶
An example showing how to locate Bluetooth devices.
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
from __future__ import annotations
"""PySide6 port of the bluetooth/btscanner example from Qt v6.x"""
import sys
from PySide6.QtWidgets import QApplication
from device import DeviceDiscoveryDialog
if __name__ == '__main__':
app = QApplication(sys.argv)
d = DeviceDiscoveryDialog()
d.exec()
sys.exit(0)
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
from __future__ import annotations
from PySide6.QtCore import QPoint, Qt, Slot
from PySide6.QtGui import QColor
from PySide6.QtWidgets import QDialog, QListWidgetItem, 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)
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
from __future__ import annotations
from PySide6.QtCore import 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::StandardButton::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>