diff options
Diffstat (limited to 'examples/bluetooth/btscanner')
-rw-r--r-- | examples/bluetooth/btscanner/btscanner.pyproject | 3 | ||||
-rw-r--r-- | examples/bluetooth/btscanner/device.py | 130 | ||||
-rw-r--r-- | examples/bluetooth/btscanner/device.ui | 111 | ||||
-rw-r--r-- | examples/bluetooth/btscanner/doc/btscanner.rst | 4 | ||||
-rw-r--r-- | examples/bluetooth/btscanner/main.py | 17 | ||||
-rw-r--r-- | examples/bluetooth/btscanner/service.py | 48 | ||||
-rw-r--r-- | examples/bluetooth/btscanner/service.ui | 71 | ||||
-rw-r--r-- | examples/bluetooth/btscanner/ui_device.py | 90 | ||||
-rw-r--r-- | examples/bluetooth/btscanner/ui_service.py | 57 |
9 files changed, 531 insertions, 0 deletions
diff --git a/examples/bluetooth/btscanner/btscanner.pyproject b/examples/bluetooth/btscanner/btscanner.pyproject new file mode 100644 index 000000000..208487fe7 --- /dev/null +++ b/examples/bluetooth/btscanner/btscanner.pyproject @@ -0,0 +1,3 @@ +{ + "files": ["main.py", "device.py", "service.py", "device.ui", "service.ui"] +} diff --git a/examples/bluetooth/btscanner/device.py b/examples/bluetooth/btscanner/device.py new file mode 100644 index 000000000..c75f5b8a1 --- /dev/null +++ b/examples/bluetooth/btscanner/device.py @@ -0,0 +1,130 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +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) diff --git a/examples/bluetooth/btscanner/device.ui b/examples/bluetooth/btscanner/device.ui new file mode 100644 index 000000000..fa81c5cb4 --- /dev/null +++ b/examples/bluetooth/btscanner/device.ui @@ -0,0 +1,111 @@ +<?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> diff --git a/examples/bluetooth/btscanner/doc/btscanner.rst b/examples/bluetooth/btscanner/doc/btscanner.rst new file mode 100644 index 000000000..d99af3be5 --- /dev/null +++ b/examples/bluetooth/btscanner/doc/btscanner.rst @@ -0,0 +1,4 @@ +Bluetooth Scanner Example +========================= + +An example showing how to locate Bluetooth devices. diff --git a/examples/bluetooth/btscanner/main.py b/examples/bluetooth/btscanner/main.py new file mode 100644 index 000000000..a54a862a2 --- /dev/null +++ b/examples/bluetooth/btscanner/main.py @@ -0,0 +1,17 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +"""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) diff --git a/examples/bluetooth/btscanner/service.py b/examples/bluetooth/btscanner/service.py new file mode 100644 index 000000000..31df8a9ea --- /dev/null +++ b/examples/bluetooth/btscanner/service.py @@ -0,0 +1,48 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +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) diff --git a/examples/bluetooth/btscanner/service.ui b/examples/bluetooth/btscanner/service.ui new file mode 100644 index 000000000..4ca12ee05 --- /dev/null +++ b/examples/bluetooth/btscanner/service.ui @@ -0,0 +1,71 @@ +<?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> diff --git a/examples/bluetooth/btscanner/ui_device.py b/examples/bluetooth/btscanner/ui_device.py new file mode 100644 index 000000000..b443b2bc2 --- /dev/null +++ b/examples/bluetooth/btscanner/ui_device.py @@ -0,0 +1,90 @@ +# -*- coding: utf-8 -*- + +################################################################################ +## Form generated from reading UI file 'device.ui' +## +## Created by: Qt User Interface Compiler version 6.7.0 +## +## WARNING! All changes made in this file will be lost when recompiling UI file! +################################################################################ + +from PySide6.QtCore import (QCoreApplication, QDate, QDateTime, QLocale, + QMetaObject, QObject, QPoint, QRect, + QSize, QTime, QUrl, Qt) +from PySide6.QtGui import (QBrush, QColor, QConicalGradient, QCursor, + QFont, QFontDatabase, QGradient, QIcon, + QImage, QKeySequence, QLinearGradient, QPainter, + QPalette, QPixmap, QRadialGradient, QTransform) +from PySide6.QtWidgets import (QApplication, QCheckBox, QDialog, QGroupBox, + QHBoxLayout, QListWidget, QListWidgetItem, QPushButton, + QSizePolicy, QVBoxLayout, QWidget) + +class Ui_DeviceDiscovery(object): + def setupUi(self, DeviceDiscovery): + if not DeviceDiscovery.objectName(): + DeviceDiscovery.setObjectName(u"DeviceDiscovery") + DeviceDiscovery.resize(400, 411) + self.verticalLayout = QVBoxLayout(DeviceDiscovery) + self.verticalLayout.setObjectName(u"verticalLayout") + self.list = QListWidget(DeviceDiscovery) + self.list.setObjectName(u"list") + + self.verticalLayout.addWidget(self.list) + + self.groupBox = QGroupBox(DeviceDiscovery) + self.groupBox.setObjectName(u"groupBox") + self.horizontalLayout_2 = QHBoxLayout(self.groupBox) + self.horizontalLayout_2.setObjectName(u"horizontalLayout_2") + self.power = QCheckBox(self.groupBox) + self.power.setObjectName(u"power") + self.power.setChecked(True) + + self.horizontalLayout_2.addWidget(self.power) + + self.discoverable = QCheckBox(self.groupBox) + self.discoverable.setObjectName(u"discoverable") + self.discoverable.setChecked(True) + + self.horizontalLayout_2.addWidget(self.discoverable) + + + self.verticalLayout.addWidget(self.groupBox) + + self.horizontalLayout = QHBoxLayout() + self.horizontalLayout.setObjectName(u"horizontalLayout") + self.scan = QPushButton(DeviceDiscovery) + self.scan.setObjectName(u"scan") + + self.horizontalLayout.addWidget(self.scan) + + self.clear = QPushButton(DeviceDiscovery) + self.clear.setObjectName(u"clear") + + self.horizontalLayout.addWidget(self.clear) + + self.quit = QPushButton(DeviceDiscovery) + self.quit.setObjectName(u"quit") + + self.horizontalLayout.addWidget(self.quit) + + + self.verticalLayout.addLayout(self.horizontalLayout) + + + self.retranslateUi(DeviceDiscovery) + self.quit.clicked.connect(DeviceDiscovery.accept) + self.clear.clicked.connect(self.list.clear) + + QMetaObject.connectSlotsByName(DeviceDiscovery) + # setupUi + + def retranslateUi(self, DeviceDiscovery): + DeviceDiscovery.setWindowTitle(QCoreApplication.translate("DeviceDiscovery", u"Bluetooth Scanner", None)) + self.groupBox.setTitle(QCoreApplication.translate("DeviceDiscovery", u"Local Device", None)) + self.power.setText(QCoreApplication.translate("DeviceDiscovery", u"Bluetooth Powered On", None)) + self.discoverable.setText(QCoreApplication.translate("DeviceDiscovery", u"Discoverable", None)) + self.scan.setText(QCoreApplication.translate("DeviceDiscovery", u"Scan", None)) + self.clear.setText(QCoreApplication.translate("DeviceDiscovery", u"Clear", None)) + self.quit.setText(QCoreApplication.translate("DeviceDiscovery", u"Quit", None)) + # retranslateUi + diff --git a/examples/bluetooth/btscanner/ui_service.py b/examples/bluetooth/btscanner/ui_service.py new file mode 100644 index 000000000..ccc36677a --- /dev/null +++ b/examples/bluetooth/btscanner/ui_service.py @@ -0,0 +1,57 @@ +# -*- coding: utf-8 -*- + +################################################################################ +## Form generated from reading UI file 'service.ui' +## +## Created by: Qt User Interface Compiler version 6.7.0 +## +## WARNING! All changes made in this file will be lost when recompiling UI file! +################################################################################ + +from PySide6.QtCore import (QCoreApplication, QDate, QDateTime, QLocale, + QMetaObject, QObject, QPoint, QRect, + QSize, QTime, QUrl, Qt) +from PySide6.QtGui import (QBrush, QColor, QConicalGradient, QCursor, + QFont, QFontDatabase, QGradient, QIcon, + QImage, QKeySequence, QLinearGradient, QPainter, + QPalette, QPixmap, QRadialGradient, QTransform) +from PySide6.QtWidgets import (QAbstractButton, QApplication, QDialog, QDialogButtonBox, + QLabel, QListWidget, QListWidgetItem, QSizePolicy, + QVBoxLayout, QWidget) + +class Ui_ServiceDiscovery(object): + def setupUi(self, ServiceDiscovery): + if not ServiceDiscovery.objectName(): + ServiceDiscovery.setObjectName(u"ServiceDiscovery") + ServiceDiscovery.resize(539, 486) + self.verticalLayout = QVBoxLayout(ServiceDiscovery) + self.verticalLayout.setObjectName(u"verticalLayout") + self.list = QListWidget(ServiceDiscovery) + self.list.setObjectName(u"list") + + self.verticalLayout.addWidget(self.list) + + self.status = QLabel(ServiceDiscovery) + self.status.setObjectName(u"status") + + self.verticalLayout.addWidget(self.status) + + self.buttonBox = QDialogButtonBox(ServiceDiscovery) + self.buttonBox.setObjectName(u"buttonBox") + self.buttonBox.setStandardButtons(QDialogButtonBox.Close) + + self.verticalLayout.addWidget(self.buttonBox) + + + self.retranslateUi(ServiceDiscovery) + self.buttonBox.accepted.connect(ServiceDiscovery.accept) + self.buttonBox.rejected.connect(ServiceDiscovery.reject) + + QMetaObject.connectSlotsByName(ServiceDiscovery) + # setupUi + + def retranslateUi(self, ServiceDiscovery): + ServiceDiscovery.setWindowTitle(QCoreApplication.translate("ServiceDiscovery", u"Available Services", None)) + self.status.setText(QCoreApplication.translate("ServiceDiscovery", u"Querying...", None)) + # retranslateUi + |