📢 Webサイト閉鎖と移転のお知らせ
このWebサイトは2026年9月に閉鎖いたします。
新しい記事は移転先で追加しております。(旧サイトでは記事を追加しておりません)
| (同じ利用者による、間の11版が非表示) | |||
| 144行目: | 144行目: | ||
* AD Data (可変長) | * AD Data (可変長) | ||
<br> | <br> | ||
[[ファイル:Qt BLE 3.png|フレームなし|中央]] | |||
<br> | |||
==== その他 (通信特性 / セキュリティ等) ==== | ==== その他 (通信特性 / セキュリティ等) ==== | ||
* 通信特性 | * 通信特性 | ||
| 165行目: | 168行目: | ||
<br> | <br> | ||
==== 使用例 ==== | ==== 使用例 ==== | ||
Qt Bluetoothモジュールを使用したBLEスキャンの処理を以下に示す。<br> | |||
<br> | |||
* QBluetoothDeviceDiscoveryAgentクラス | |||
* QBluetoothDeviceInfoクラス | |||
<br> | |||
===== デバイス探索エージェントの作成 ===== | |||
QBluetoothDeviceDiscoveryAgentのインスタンスを生成する。<br> | |||
<br> | |||
<syntaxhighlight lang="c++"> | |||
#include <QBluetoothDeviceDiscoveryAgent> | |||
QBluetoothDeviceDiscoveryAgent discoveryAgent; | |||
</syntaxhighlight> | |||
<br> | |||
===== シグナル / スロット接続 ===== | |||
* QBluetoothDeviceDiscoveryAgent::deviceDiscoveredシグナル | |||
*: デバイスを発見した時に送信される。 | |||
* QBluetoothDeviceDiscoveryAgent::finished | |||
*: スキャンが完了した時に送信される。 | |||
* QBluetoothDeviceDiscoveryAgent::error | |||
*: エラーが発生した時に送信される。 | |||
<br> | |||
<syntaxhighlight lang="c++"> | <syntaxhighlight lang="c++"> | ||
// デバイス発見時 | |||
connect(discoveryAgent, &QBluetoothDeviceDiscoveryAgent::deviceDiscovered, this, &MyClass::onDeviceDiscovered); | |||
// スキャン完了時 | |||
connect(discoveryAgent, &QBluetoothDeviceDiscoveryAgent::finished, this, &MyClass::onScanFinished); | |||
// エラー発生時 | |||
// エラーハンドリングは必ず実装する | |||
connect(discoveryAgent, &QBluetoothDeviceDiscoveryAgent::error, this, &MyClass::onError); | |||
</syntaxhighlight> | |||
<br> | |||
===== スキャン開始 ===== | |||
<code>QBluetoothDeviceDiscoveryAgent::LowEnergyMethod</code>メソッドを指定して、<code>QBluetoothDeviceDiscoveryAgent::start</code>メソッドを実行する。<br> | |||
これによりBLEデバイスのスキャンが開始する。<br> | |||
<br> | |||
<syntaxhighlight lang="c++"> | |||
discoveryAgent->start(QBluetoothDeviceDiscoveryAgent::LowEnergyMethod); | |||
</syntaxhighlight> | |||
<br> | |||
===== デバイス発見時 ===== | |||
<code>QBluetoothDeviceDiscoveryAgent::deviceDiscovered</code>シグナルで通知する。<br> | |||
<code>QBluetoothDeviceInfo</code>クラスを使用して、以下に示す情報を取得することが可能である。<br> | |||
* デバイス名 | |||
* アドレス | |||
* 信号強度 (RSSI値) | |||
* サービスUUID | |||
* マニファクチャラーデータ | |||
<br> | |||
<u>ただし、これらの情報を取得する前は、必ず存在確認を行う。</u><br> | |||
<br> | |||
<syntaxhighlight lang="c++"> | |||
void onDeviceDiscovered(const QBluetoothDeviceInfo &device) | |||
{ | |||
// デバイス名の取得 | |||
QString name = device.name(); | |||
// アドレスの取得 | |||
QString address = device.address().toString(); | |||
// RSSI値の取得 | |||
qint16 rssi = device.rssi(); | |||
// サービスUUIDの取得 | |||
QList<QBluetoothUuid> services = device.serviceUuids(); | |||
// マニファクチャラーデータの取得 | |||
QMap<quint16, QByteArray> manufacturerData = device.manufacturerData(); | |||
} | |||
</syntaxhighlight> | |||
<br> | |||
===== スキャン完了時 ===== | |||
<code>QBluetoothDeviceDiscoveryAgent::finished</code>シグナルで送信する。<br> | |||
<br> | |||
スキャン完了時の処理を記述する。<br> | |||
また、必要に応じて再スキャンを開始する。<br> | |||
<br> | |||
<syntaxhighlight lang="c++"> | |||
void onScanFinished() | |||
{ | |||
// 必要に応じて再スキャン | |||
discoveryAgent->start(QBluetoothDeviceDiscoveryAgent::LowEnergyMethod); | |||
} | |||
</syntaxhighlight> | |||
<br> | |||
===== エラー発生時 ===== | |||
リソースの解放は適切に行う。<br> | |||
<br> | |||
<syntaxhighlight lang="c++"> | |||
void onError(QBluetoothDeviceDiscoveryAgent::Error error) | |||
{ | |||
switch (error) { | |||
case QBluetoothDeviceDiscoveryAgent::NoError: | |||
break; | |||
case QBluetoothDeviceDiscoveryAgent::InputOutputError: | |||
break; | |||
case QBluetoothDeviceDiscoveryAgent::PoweredOffError: | |||
break; | |||
case QBluetoothDeviceDiscoveryAgent::InvalidBluetoothAdapterError: | |||
break; | |||
case QBluetoothDeviceDiscoveryAgent::UnsupportedPlatformError: | |||
break; | |||
case QBluetoothDeviceDiscoveryAgent::UnsupportedDiscoveryMethod: | |||
break; | |||
default: | |||
break; | |||
} | |||
} | |||
</syntaxhighlight> | |||
<br> | |||
===== スキャン停止 ===== | |||
<syntaxhighlight lang="c++"> | |||
discoveryAgent->stop(); | |||
</syntaxhighlight> | |||
<br> | |||
===== 組み合わせ ===== | |||
<syntaxhighlight lang="c++"> | |||
// BLEデバイスのスキャンを管理するクラス | |||
// BLEデバイスの検出と監視, 継続的なスキャンモード, デバイス情報の重複排除, 自動リカバリを行う | |||
#include <QObject> | #include <QObject> | ||
#include <QBluetoothDeviceDiscoveryAgent> | #include <QBluetoothDeviceDiscoveryAgent> | ||
#include <QBluetoothDeviceInfo> | #include <QBluetoothDeviceInfo> | ||
#include <QTimer> | #include <QTimer> | ||
#include <QDebug> | #include <QDebug> | ||
| 178行目: | 301行目: | ||
private: | private: | ||
QBluetoothDeviceDiscoveryAgent discoveryAgent; // BLEデバイス探索用エージェント | |||
QTimer rescanTimer; // 継続的スキャン用タイマ | |||
bool isContinuousScan = false; | bool isContinuousScan = false; // 継続的スキャンモードのフラグ | ||
QMap<QBluetoothAddress, QBluetoothDeviceInfo> knownDevices; // 既知デバイスのキャッシュ | |||
// デバイス探索エージェントとタイマーのシグナルを適切なスロットに接続 | |||
// デバイス発見時の処理, スキャン完了時の処理, エラー発生時の処理, 定期的な再スキャンの制御を行う | |||
void connectSignals() | void connectSignals() | ||
{ | { | ||
// デバイス探索エージェントのシグナル接続 | // デバイス探索エージェントのシグナル接続 | ||
connect(discoveryAgent | connect(&discoveryAgent, &QBluetoothDeviceDiscoveryAgent::deviceDiscovered, this, &BLEDeviceScanner::onDeviceDiscovered); | ||
connect(discoveryAgent | connect(&discoveryAgent, &QBluetoothDeviceDiscoveryAgent::finished, this, &BLEDeviceScanner::onScanFinished); | ||
connect(discoveryAgent | connect(&discoveryAgent, static_cast<void(QBluetoothDeviceDiscoveryAgent::*)(QBluetoothDeviceDiscoveryAgent::Error)>(&QBluetoothDeviceDiscoveryAgent::error), | ||
this, &BLEDeviceScanner::onError); | this, &BLEDeviceScanner::onError); | ||
// 再スキャンタイマのシグナル接続 | // 再スキャンタイマのシグナル接続 | ||
connect(rescanTimer | connect(&rescanTimer, &QTimer::timeout, this, [this]() { | ||
if (isContinuousScan) { | if (isContinuousScan) { | ||
discoveryAgent | discoveryAgent.start(QBluetoothDeviceDiscoveryAgent::LowEnergyMethod); | ||
} | } | ||
}); | }); | ||
} | } | ||
// エラーコード | |||
QString getErrorMessage(QBluetoothDeviceDiscoveryAgent::Error error) | QString getErrorMessage(QBluetoothDeviceDiscoveryAgent::Error error) | ||
{ | { | ||
| 208行目: | 335行目: | ||
case QBluetoothDeviceDiscoveryAgent::UnsupportedDiscoveryMethod: return "未対応の探索方法"; | case QBluetoothDeviceDiscoveryAgent::UnsupportedDiscoveryMethod: return "未対応の探索方法"; | ||
default: return "不明なエラー"; | default: return "不明なエラー"; | ||
} | |||
} | |||
// 発見されたデバイスの詳細情報をログに出力 | |||
// デバイス名, MACアドレス, 電波強度 (RSSI), 提供サービスのUUID, メーカー固有データを表示 | |||
void logDeviceInfo(const QBluetoothDeviceInfo& device) | |||
{ | |||
qDebug() << "BLEデバイスを発見:"; | |||
qDebug() << " 名前:" << device.name(); | |||
qDebug() << " アドレス:" << device.address().toString(); | |||
qDebug() << " RSSI:" << device.rssi(); | |||
// サービスUUIDのログ出力 | |||
const QList<QBluetoothUuid> serviceUuids = device.serviceUuids(); | |||
if (!serviceUuids.isEmpty()) { | |||
qDebug() << " 提供サービス:"; | |||
for (const QBluetoothUuid& uuid : serviceUuids) { | |||
qDebug() << " -" << uuid.toString(); | |||
} | |||
} | |||
// マニファクチャラーデータのログ出力 | |||
const QMap<quint16, QByteArray> manufacturerData = device.manufacturerData(); | |||
if (!manufacturerData.isEmpty()) { | |||
qDebug() << " マニファクチャラーデータ:"; | |||
QMap<quint16, QByteArray>::const_iterator i = manufacturerData.constBegin(); | |||
while (i != manufacturerData.constEnd()) { | |||
qDebug() << " ID: " << i.key() << "データ: " << i.value().toHex(); | |||
i++; | |||
} | |||
} | } | ||
} | } | ||
| 214行目: | 371行目: | ||
explicit BLEDeviceScanner(QObject* parent = nullptr) : QObject(parent) | explicit BLEDeviceScanner(QObject* parent = nullptr) : QObject(parent) | ||
{ | { | ||
// BLEデバイスのみをスキャンするように設定 | // BLEデバイスのみをスキャンするように設定 | ||
discoveryAgent | discoveryAgent.setLowEnergyDiscoveryTimeout(10000); // 10秒のタイムアウト | ||
// 自動再スキャンタイマの設定 | // 自動再スキャンタイマの設定 | ||
rescanTimer | rescanTimer.setInterval(30000); // 30秒間隔で再スキャン | ||
connectSignals(); | connectSignals(); | ||
} | } | ||
// | // BLEデバイスのスキャンを開始 | ||
void startScan(bool continuous = false) | void startScan(bool continuous = false) | ||
{ | { | ||
| 233行目: | 386行目: | ||
qDebug() << "BLEデバイススキャンを開始..."; | qDebug() << "BLEデバイススキャンを開始..."; | ||
isContinuousScan = continuous; | isContinuousScan = continuous; | ||
discoveryAgent | discoveryAgent.start(QBluetoothDeviceDiscoveryAgent::LowEnergyMethod); | ||
if (continuous) rescanTimer | if (continuous) rescanTimer.start(); | ||
emit scanStarted(); | emit scanStarted(); | ||
| 251行目: | 404行目: | ||
try { | try { | ||
qDebug() << "BLEデバイススキャンを停止..."; | qDebug() << "BLEデバイススキャンを停止..."; | ||
discoveryAgent | discoveryAgent.stop(); | ||
rescanTimer | rescanTimer.stop(); | ||
isContinuousScan = false; | isContinuousScan = false; | ||
emit scanStopped(); | emit scanStopped(); | ||
| 264行目: | 417行目: | ||
signals: | signals: | ||
void deviceDiscovered(const QBluetoothDeviceInfo& device); | void deviceDiscovered(const QBluetoothDeviceInfo& device); // 新規デバイス発見時 | ||
void scanStarted(); | void scanStarted(); // スキャン開始時 | ||
void scanStopped(); | void scanStopped(); // スキャン停止時 | ||
void scanFinished(); | void scanFinished(); // スキャン完了時 | ||
void errorOccurred(const QString& error); | void errorOccurred(const QString& error); // エラー発生時 | ||
private slots: | private slots: | ||
// デバイス発見時の処理 | |||
// BLEデバイスのフィルタリング, 重複デバイスの検出と更新, デバイス情報のログ出力, 新規 / 更新デバイスの通知 | |||
void onDeviceDiscovered(const QBluetoothDeviceInfo& device) | void onDeviceDiscovered(const QBluetoothDeviceInfo& device) | ||
{ | { | ||
// BLEデバイスのみを処理 | // BLEデバイスのみを処理 | ||
if (!(device.coreConfigurations() & QBluetoothDeviceInfo::LowEnergyCoreConfiguration)) { | |||
return; | |||
} | |||
// デバイスの重複確認 | |||
const QBluetoothAddress& address = device.address(); | |||
if (!knownDevices.contains(address) || knownDevices[address].rssi() != device.rssi()) { | |||
knownDevices[address] = device; | |||
// デバイス情報のログ出力と通知 | |||
logDeviceInfo(device); | |||
emit deviceDiscovered(device); | |||
} | |||
} | } | ||
// スキャン完了時の処理 | |||
// 完了通知の発行, 継続的スキャンモードの場合は1秒後に再スキャン | |||
void onScanFinished() | void onScanFinished() | ||
{ | { | ||
| 312行目: | 454行目: | ||
if (isContinuousScan) { | if (isContinuousScan) { | ||
QTimer::singleShot(1000, this, [this]() { | QTimer::singleShot(1000, this, [this]() { | ||
discoveryAgent | discoveryAgent.start(QBluetoothDeviceDiscoveryAgent::LowEnergyMethod); | ||
}); | }); | ||
} | } | ||
} | } | ||
// エラー発生時の処理 (エラーメッセージの生成とログ出力) | |||
// 継続的スキャンモードの場合は5秒後に自動再試行 | |||
void onError(QBluetoothDeviceDiscoveryAgent::Error error) | void onError(QBluetoothDeviceDiscoveryAgent::Error error) | ||
{ | { | ||
| 326行目: | 470行目: | ||
if (isContinuousScan) { | if (isContinuousScan) { | ||
QTimer::singleShot(5000, this, [this]() { | QTimer::singleShot(5000, this, [this]() { | ||
discoveryAgent | discoveryAgent.start(QBluetoothDeviceDiscoveryAgent::LowEnergyMethod); | ||
}); | }); | ||
} | } | ||
| 385行目: | 529行目: | ||
<br> | <br> | ||
==== 使用例 ==== | ==== 使用例 ==== | ||
===== QLowEnergyControllerクラスのインスタンスの生成 ===== | |||
まず、<code>QBluetoothDeviceDiscoveryAgent</code>クラスを使用して、スキャンを実行する。<br> | |||
<br> | |||
次に、接続するデバイスの<code>QBluetoothDeviceInfo</code>クラスのデバイス情報を取得する。<br> | |||
取得したデバイス情報を元に、<code>QLowEnergyController</code>クラスのインスタンスを生成する。<br> | |||
<br> | |||
===== コントローラのシグナル / スロット接続 ===== | |||
最低限必要なシグナルを示す。<br> | |||
* connected | |||
*: デバイスへの接続完了を通知 | |||
* disconnected | |||
*: デバイスとの切断を通知 | |||
* serviceDiscovered | |||
*: 新しいサービスの発見を通知 | |||
* discoveryFinished | |||
*: サービス探索の完了を通知 | |||
<br> | |||
===== BLEデバイスの接続 ===== | |||
connectToDeviceメソッドを実行してBLEデバイスに接続する。<br> | |||
connectedシグナルの受信を待つ。<br> | |||
<br> | |||
===== サービスの探索 ===== | |||
BLEデバイスへ接続後、discoverServicesメソッドを実行してサービスの探索を開始する。<br> | |||
<br> | |||
* serviceDiscoveredシグナルで個々のサービスが見つかる度に通知される。 | |||
* discoveryFinishedシグナルで探索完了が通知される。 | |||
<br> | |||
===== サービスの取得 ===== | |||
createServiceObjectメソッドをを実行して、探索で発見したサービスのQLowEnergyServiceオブジェクトを生成する。<br> | |||
このオブジェクトを使用して、特性 (Characteristic) や ディスクリプタにアクセスできる。<br> | |||
<br> | |||
===== 組み合わせ ===== | |||
<syntaxhighlight lang="c++"> | <syntaxhighlight lang="c++"> | ||
// BLEのサービス探索を管理するクラス | |||
// BLEデバイスへの接続, サービスの探索と監視 | |||
#include <QObject> | #include <QObject> | ||
#include <QLowEnergyController> | #include <QLowEnergyController> | ||
#include <QLowEnergyService> | #include <QLowEnergyService> | ||
#include <QTimer> | #include <QTimer> | ||
#include <QDebug> | #include <QDebug> | ||
| 398行目: | 576行目: | ||
private: | private: | ||
QLowEnergyController controller; // BLE接続とサービス探索を制御するコントローラ | |||
QTimer discoveryTimeout; // サービス探索のタイムアウトを管理するタイマ | |||
// コントローラの各種シグナルを接続 | |||
// 接続 / 切断, サービス探索の進行状況, 状態変更, エラー | |||
void connectControllerSignals() | void connectControllerSignals() | ||
{ | { | ||
connect(controller | connect(&controller, &QLowEnergyController::connected, this, &BLEServiceDiscovery::onConnected); | ||
connect(controller | connect(&controller, &QLowEnergyController::disconnected, this, &BLEServiceDiscovery::onDisconnected); | ||
connect(controller | connect(&controller, &QLowEnergyController::serviceDiscovered, this, &BLEServiceDiscovery::onServiceDiscovered); | ||
connect(controller | connect(&controller, &QLowEnergyController::discoveryFinished, this, &BLEServiceDiscovery::onDiscoveryFinished); | ||
connect(controller | connect(&controller, static_cast<void(QLowEnergyController::*)(QLowEnergyController::Error)>(&QLowEnergyController::error), this, &BLEServiceDiscovery::onError); | ||
connect(controller | connect(&controller, &QLowEnergyController::stateChanged, this, &BLEServiceDiscovery::onStateChanged); | ||
} | } | ||
// 個別のBLEサービスに対するシグナル | |||
// 状態変更とエラーイベントを監視してログを出力する | |||
void connectServiceSignals(QLowEnergyService *service) | void connectServiceSignals(QLowEnergyService *service) | ||
{ | { | ||
| 422行目: | 604行目: | ||
} | } | ||
// エラーコードの変換 | |||
QString getErrorMessage(QLowEnergyController::Error error) | QString getErrorMessage(QLowEnergyController::Error error) | ||
{ | { | ||
| 478行目: | 661行目: | ||
{ | { | ||
// タイムアウトタイマの初期化 | // タイムアウトタイマの初期化 | ||
discoveryTimeout | discoveryTimeout.setInterval(10000); // 10秒のタイムアウト | ||
discoveryTimeout.setSingleShot(true); | |||
discoveryTimeout | |||
connect(discoveryTimeout | connect(&discoveryTimeout, &QTimer::timeout, this, &BLEServiceDiscovery::onDiscoveryTimeout); | ||
} | } | ||
// デバイスへの接続とサービス探索の開始 | // デバイスへの接続とサービス探索の開始 | ||
void startDiscovery(const QBluetoothDeviceInfo& device) | // コントローラの初期化, シグナルの接続, デバイスへの接続開始, タイムアウトタイマの開始 | ||
void startDiscovery(const QBluetoothDeviceInfo &device) | |||
{ | { | ||
try { | try { | ||
| 492行目: | 675行目: | ||
// コントローラの初期化 | // コントローラの初期化 | ||
connectControllerSignals(); | connectControllerSignals(); | ||
// 接続開始 | // 接続開始 | ||
controller | controller.connectToDevice(); | ||
discoveryTimeout | discoveryTimeout.start(); | ||
} | } | ||
catch (const std::exception &e) { | catch (const std::exception &e) { | ||
| 506行目: | 688行目: | ||
} | } | ||
// 探索を停止 | // 探索を停止 (タイムアウトタイマも停止) | ||
void stopDiscovery() | void stopDiscovery() | ||
{ | { | ||
try { | try { | ||
if (controller) { | if (controller) { | ||
controller | controller.disconnectFromDevice(); | ||
discoveryTimeout | discoveryTimeout.stop(); | ||
} | } | ||
} | } | ||
| 523行目: | 705行目: | ||
signals: | signals: | ||
void serviceDiscovered(QLowEnergyService *service); | void serviceDiscovered(QLowEnergyService *service); // 新しいサービスが発見された時に発行 | ||
void discoveryComplete(); | void discoveryComplete(); // 全てのサービス探索が完了した時に発行 | ||
void errorOccurred(const QString &error); | void errorOccurred(const QString &error); // エラーが発生した時に発行 | ||
void connectionStateChanged(QLowEnergyController::ControllerState state); | void connectionStateChanged(QLowEnergyController::ControllerState state); // 接続状態が変更された時に発行 | ||
private slots: | private slots: | ||
// デバイスへの接続が完了した時 (タイムアウトタイマを停止して、サービス探索を開始) | |||
void onConnected() | void onConnected() | ||
{ | { | ||
qDebug() << "デバイスに接続"; | qDebug() << "デバイスに接続"; | ||
discoveryTimeout | discoveryTimeout.stop(); | ||
// サービス探索の開始 | // サービス探索の開始 | ||
controller | controller.discoverServices(); | ||
} | } | ||
// デバイスから切断された時 (タイムアウトタイマを停止) | |||
void onDisconnected() | void onDisconnected() | ||
{ | { | ||
qDebug() << "デバイスから切断"; | qDebug() << "デバイスから切断"; | ||
discoveryTimeout | discoveryTimeout.stop(); | ||
} | } | ||
// 新しいサービスが発見された時 | |||
void onServiceDiscovered(const QBluetoothUuid& uuid) | void onServiceDiscovered(const QBluetoothUuid& uuid) | ||
{ | { | ||
| 549行目: | 734行目: | ||
// サービスオブジェクトの作成 | // サービスオブジェクトの作成 | ||
QLowEnergyService* service = controller | QLowEnergyService* service = controller.createServiceObject(uuid, this); | ||
if (service) { | if (service) { | ||
connectServiceSignals(service); | connectServiceSignals(service); | ||
| 556行目: | 741行目: | ||
} | } | ||
// サービス探索が完了した時 | |||
void onDiscoveryFinished() | void onDiscoveryFinished() | ||
{ | { | ||
qDebug() << "サービス探索が完了"; | qDebug() << "サービス探索が完了"; | ||
discoveryTimeout | discoveryTimeout.stop(); | ||
emit discoveryComplete(); | emit discoveryComplete(); | ||
} | } | ||
// エラーが発生した時 | |||
void onError(QLowEnergyController::Error error) | void onError(QLowEnergyController::Error error) | ||
{ | { | ||
| 570行目: | 757行目: | ||
} | } | ||
// タイムアウトが発生した時 (探索を停止して、エラーとして通知) | |||
void onDiscoveryTimeout() | void onDiscoveryTimeout() | ||
{ | { | ||
| 577行目: | 765行目: | ||
} | } | ||
// 接続状態が変更された時 (状態の変更をログ出力して、通知) | |||
void onStateChanged(QLowEnergyController::ControllerState state) | void onStateChanged(QLowEnergyController::ControllerState state) | ||
{ | { | ||
| 651行目: | 840行目: | ||
<br> | <br> | ||
==== 使用例 ==== | ==== 使用例 ==== | ||
===== ローカルデバイスの初期化 ===== | |||
BLEデバイスを利用するため、QBluetoothLocalDeviceクラスを使用して初期化する。<br> | |||
初期化時にBLEデバイスが有効かどうかの確認を行う。<br> | |||
<br> | |||
* QBluetoothLocalDeviceクラス | |||
* QBluetoothAddressクラス | |||
<br> | |||
<syntaxhighlight lang="c++"> | |||
#include <QBluetoothLocalDevice> | |||
#include <QBluetoothAddress> | |||
QBluetoothLocalDevice localDevice; | |||
if (!localDevice.isValid()) { | |||
qDebug() << "Bluetoothデバイスが利用できません"; | |||
return; | |||
} | |||
</syntaxhighlight> | |||
<br> | |||
===== ペアリング状態の変化を監視 ===== | |||
ペアリングの結果を受信すため、<code>QBluetoothLocalDevice::pairingFinished</code>シグナルに接続する。<br> | |||
これにより、ペアリング成功 / 失敗の通知を受け取ることができる。<br> | |||
<br> | |||
<syntaxhighlight lang="c++"> | |||
connect(&localDevice, &QBluetoothLocalDevice::pairingFinished, [](const QBluetoothAddress &address, QBluetoothLocalDevice::Pairing pairing) { | |||
if (pairing == QBluetoothLocalDevice::Paired) { | |||
qDebug() << "ペアリング成功:" << address.toString(); | |||
} | |||
else { | |||
qDebug() << "ペアリング失敗:" << address.toString(); | |||
} | |||
}); | |||
</syntaxhighlight> | |||
<br> | |||
===== PINコード確認のシグナル (必要な場合のみ) ===== | |||
PINコードが必要なデバイスは、<code>BluetoothLocalDevice::pairingDisplayConfirmation</code>シグナルに接続する。<br> | |||
これにより、PINコードの確認が必要な場合に通知を受け取ることができる。<br> | |||
<br> | |||
<syntaxhighlight lang="c++"> | |||
connect(&localDevice, &QBluetoothLocalDevice::pairingDisplayConfirmation, [](const QBluetoothAddress &address, QString pin) { | |||
qDebug() << "PINコード確認: " << address.toString() << pin; | |||
}); | |||
</syntaxhighlight> | |||
<br> | |||
===== ペアリング要求 ===== | |||
ペアリングを開始するため、ペアリングするデバイスのBluetoothアドレスを指定して、<code>QBluetoothLocalDevice::requestPairing</code>メソッドを実行する。<br> | |||
<br> | |||
ペアリングの結果は、<code>QBluetoothLocalDevice::pairingFinished</code>シグナルで受信して、成功 / 失敗に応じた処理を行う。<br> | |||
<br> | |||
<syntaxhighlight lang="c++"> | <syntaxhighlight lang="c++"> | ||
QBluetoothAddress targetAddress("XX:XX:XX:XX:XX:XX"); // 接続先アドレス | |||
localDevice.requestPairing(targetAddress, QBluetoothLocalDevice::Paired); | |||
</syntaxhighlight> | |||
<br> | |||
===== 組み合わせ ===== | |||
<syntaxhighlight lang="c++"> | |||
// BLEデバイスとのペアリング操作を管理するクラス | |||
// ペアリングの開始と解除, ペアリング状態の監視, PINコード認証 | |||
#include <QObject> | #include <QObject> | ||
#include <QBluetoothLocalDevice> | #include <QBluetoothLocalDevice> | ||
#include <QBluetoothAddress> | #include <QBluetoothAddress> | ||
#include <QDebug> | #include <QDebug> | ||
| 663行目: | 908行目: | ||
private: | private: | ||
QBluetoothLocalDevice localDevice; // ローカルのBLEデバイスを管理するオブジェクト | |||
// ペアリング状態を表す文字列 | |||
QString getPairingStatusString(QBluetoothLocalDevice::Pairing status) | QString getPairingStatusString(QBluetoothLocalDevice::Pairing status) | ||
{ | { | ||
| 673行目: | 919行目: | ||
default: return "不明な状態"; | default: return "不明な状態"; | ||
} | } | ||
} | |||
// BLEデバイスが使用可能な状態かどうかを確認 | |||
bool isDeviceReady() const | |||
{ | |||
if (!localDevice || !localDevice->isValid()) return false; | |||
return localDevice.hostMode() != QBluetoothLocalDevice::HostPoweredOff; | |||
} | |||
// BLEデバイスのホストモードを設定 | |||
void setHostMode(QBluetoothLocalDevice::HostMode mode) | |||
{ | |||
if (isDeviceReady()) localDevice.setHostMode(mode); | |||
} | |||
// ホスト側においてBLEが利用可能かどうかを確認 | |||
bool isBluetoothAvailable() const | |||
{ | |||
return QBluetoothLocalDevice::allDevices().count() > 0; | |||
} | } | ||
public: | public: | ||
explicit BLEPairing(QObject* parent = nullptr) : QObject(parent) | explicit BLEPairing(QObject *parent = nullptr) : QObject(parent) | ||
{ | { | ||
try { | try { | ||
// シグナルの接続 | // シグナルの接続 | ||
connect(localDevice | connect(&localDevice, &QBluetoothLocalDevice::pairingFinished, this, &BLEPairing::onPairingFinished); | ||
connect(localDevice | connect(&localDevice, &QBluetoothLocalDevice::error, this, &BLEPairing::onError); | ||
connect(localDevice | connect(&localDevice, &QBluetoothLocalDevice::pairingDisplayConfirmation, this, &BLEPairing::onPairingDisplayConfirmation); | ||
connect(localDevice | connect(&localDevice, &QBluetoothLocalDevice::pairingDisplayPinCode, this, &BLEPairing::onPairingDisplayPinCode); | ||
} | } | ||
catch (const std::exception &e) { | catch (const std::exception &e) { | ||
| 694行目: | 956行目: | ||
} | } | ||
// | ~BLEPairing() | ||
{ | |||
if (localDevice) { | |||
disconnect(&localDevice); // 全ての接続を解除 | |||
} | |||
} | |||
// 指定したデバイスとのペアリングを開始 | |||
// 30秒のタイムアウトを設定 (失敗時はエラーを通知) | |||
void requestPairing(const QBluetoothAddress &address) | void requestPairing(const QBluetoothAddress &address) | ||
{ | { | ||
try { | try { | ||
if (! | if (!isDeviceReady()) { | ||
emit errorOccurred("ローカルBluetoothデバイスが無効です"); | emit errorOccurred("ローカルBluetoothデバイスが無効です"); | ||
return; | return; | ||
} | } | ||
// タイムアウトの設定 | |||
QTimer::singleShot(30000, this, [this, address]() { | |||
if (getPairingStatus(address) != QBluetoothLocalDevice::Paired) { | |||
emit errorOccurred("ペアリングがタイムアウトしました"); | |||
} | |||
}); | |||
qDebug() << "ペアリングを開始: " << address.toString(); | qDebug() << "ペアリングを開始: " << address.toString(); | ||
localDevice | localDevice.requestPairing(address, QBluetoothLocalDevice::Paired); | ||
} | } | ||
catch (const std::exception &e) { | catch (const std::exception &e) { | ||
emit errorOccurred("ペアリング開始時に予期せぬエラーが発生しました"); | |||
} | } | ||
} | } | ||
// | // 指定したBLEデバイスとのペアリングを解除 | ||
void removePairing(const QBluetoothAddress& address) | void removePairing(const QBluetoothAddress& address) | ||
{ | { | ||
try { | try { | ||
if (!localDevice | if (!localDevice.isValid()) { | ||
emit errorOccurred("ローカルBluetoothデバイスが無効"); | emit errorOccurred("ローカルBluetoothデバイスが無効"); | ||
return; | return; | ||
| 723行目: | 998行目: | ||
qDebug() << "ペアリングを解除: " << address.toString(); | qDebug() << "ペアリングを解除: " << address.toString(); | ||
localDevice | localDevice.requestPairing(address, QBluetoothLocalDevice::Unpaired); | ||
} | } | ||
catch (const std::exception &e) { | catch (const std::exception &e) { | ||
| 732行目: | 1,007行目: | ||
} | } | ||
// | // 指定したBLEデバイスとのペアリング状態を確認 | ||
QBluetoothLocalDevice::Pairing getPairingStatus(const QBluetoothAddress &address) | QBluetoothLocalDevice::Pairing getPairingStatus(const QBluetoothAddress &address) | ||
{ | { | ||
try { | try { | ||
if (!localDevice | if (!localDevice.isValid()) { | ||
emit errorOccurred("ローカルBluetoothデバイスが無効"); | emit errorOccurred("ローカルBluetoothデバイスが無効"); | ||
return QBluetoothLocalDevice::Unpaired; | return QBluetoothLocalDevice::Unpaired; | ||
} | } | ||
return localDevice | return localDevice.pairingStatus(address); | ||
} | } | ||
catch (const std::exception &e) { | catch (const std::exception &e) { | ||
| 752行目: | 1,027行目: | ||
signals: | signals: | ||
void pairingComplete(const QBluetoothAddress& address, bool success); | void pairingComplete(const QBluetoothAddress& address, bool success); // ペアリング完了通知 | ||
void pairingConfirmationRequired(const QBluetoothAddress& address, QString pin); | void pairingConfirmationRequired(const QBluetoothAddress& address, QString pin); // PIN確認要求通知 | ||
void errorOccurred(const QString& error); | void errorOccurred(const QString& error); // エラー通知 | ||
private slots: | private slots: | ||
// ペアリング完了時 | |||
void onPairingFinished(const QBluetoothAddress &address, QBluetoothLocalDevice::Pairing pairing) | void onPairingFinished(const QBluetoothAddress &address, QBluetoothLocalDevice::Pairing pairing) | ||
{ | { | ||
| 764行目: | 1,040行目: | ||
} | } | ||
// BLEエラー発生時 | |||
void onError() | void onError() | ||
{ | { | ||
QString errorMsg = " | QBluetoothLocalDevice::Error error = localDevice->error(); | ||
qDebug() << errorMsg; | QString errorMsg; | ||
switch (error) { | |||
case QBluetoothLocalDevice::NoError: | |||
errorMsg = "エラーなし"; | |||
break; | |||
case QBluetoothLocalDevice::PairingError: | |||
errorMsg = "ペアリングエラー"; | |||
break; | |||
case QBluetoothLocalDevice::UnknownError: | |||
default: | |||
errorMsg = "不明なエラー"; | |||
break; | |||
} | |||
qDebug() << "Bluetoothエラー: " << errorMsg; | |||
emit errorOccurred(errorMsg); | emit errorOccurred(errorMsg); | ||
} | } | ||
// ペアリング時のPIN確認要求処理 | |||
void onPairingDisplayConfirmation(const QBluetoothAddress &address, QString pin) | void onPairingDisplayConfirmation(const QBluetoothAddress &address, QString pin) | ||
{ | { | ||
| 779行目: | 1,072行目: | ||
} | } | ||
// PINコード表示要求時 | |||
void onPairingDisplayPinCode(const QBluetoothAddress &address, QString pin) | void onPairingDisplayPinCode(const QBluetoothAddress &address, QString pin) | ||
{ | { | ||
| 813行目: | 1,107行目: | ||
#include <QLowEnergyCharacteristic> | #include <QLowEnergyCharacteristic> | ||
#include <QTimer> | #include <QTimer> | ||
#include <QDebug> | #include <QDebug> | ||
| 821行目: | 1,114行目: | ||
private: | private: | ||
QLowEnergyController controller; | |||
QTimer reconnectTimer; | |||
QBluetoothDeviceInfo currentDevice; | QBluetoothDeviceInfo currentDevice; | ||
bool autoReconnect = false; | bool autoReconnect = false; | ||
| 828行目: | 1,121行目: | ||
void connectControllerSignals() | void connectControllerSignals() | ||
{ | { | ||
connect(controller | connect(&controller, &QLowEnergyController::connected, this, &BLEConnection::onConnected); | ||
connect(controller | connect(&controller, &QLowEnergyController::disconnected, this, &BLEConnection::onDisconnected); | ||
connect(controller | connect(&controller, &QLowEnergyController::serviceDiscovered, this, &BLEConnection::onServiceDiscovered); | ||
connect(controller | connect(&controller, static_cast<void(QLowEnergyController::*)(QLowEnergyController::Error)>(&QLowEnergyController::error), this, &BLEConnection::onError); | ||
connect(controller | connect(&controller, &QLowEnergyController::stateChanged, this, &BLEConnection::onStateChanged); | ||
} | } | ||
| 943行目: | 1,236行目: | ||
{ | { | ||
// 再接続タイマの初期化 | // 再接続タイマの初期化 | ||
reconnectTimer | reconnectTimer.setInterval(5000); // 5秒間隔で再接続 | ||
reconnectTimer.setSingleShot(true); | |||
reconnectTimer | |||
connect(reconnectTimer | connect(&reconnectTimer &QTimer::timeout, this, &BLEConnection::onReconnectTimeout); | ||
} | } | ||
| 957行目: | 1,249行目: | ||
// コントローラの初期化 | // コントローラの初期化 | ||
connectControllerSignals(); | connectControllerSignals(); | ||
// 接続パラメータの設定 | // 接続パラメータの設定 | ||
controller | controller.setRemoteAddressType(QLowEnergyController::PublicAddress); | ||
// 接続開始 | // 接続開始 | ||
controller | controller.connectToDevice(); | ||
currentDevice = device; | currentDevice = device; | ||
} | } | ||
| 979行目: | 1,270行目: | ||
try { | try { | ||
if (controller) { | if (controller) { | ||
controller | controller.disconnectFromDevice(); | ||
reconnectTimer | reconnectTimer.stop(); | ||
} | } | ||
} | } | ||
| 995行目: | 1,286行目: | ||
autoReconnect = enable; | autoReconnect = enable; | ||
if (!enable) { | if (!enable) { | ||
reconnectTimer | reconnectTimer.stop(); | ||
} | } | ||
} | } | ||
| 1,010行目: | 1,301行目: | ||
{ | { | ||
qDebug() << "デバイスに接続"; | qDebug() << "デバイスに接続"; | ||
reconnectTimer | reconnectTimer.stop(); | ||
emit connected(); | emit connected(); | ||
// サービスの探索を開始 | // サービスの探索を開始 | ||
controller | controller.discoverServices(); | ||
} | } | ||
| 1,025行目: | 1,316行目: | ||
if (autoReconnect) { | if (autoReconnect) { | ||
qDebug() << "再接続を試行..."; | qDebug() << "再接続を試行..."; | ||
reconnectTimer | reconnectTimer.start(); | ||
} | } | ||
} | } | ||
| 1,033行目: | 1,324行目: | ||
qDebug() << "サービスを発見: " << uuid.toString(); | qDebug() << "サービスを発見: " << uuid.toString(); | ||
QLowEnergyService* service = controller | QLowEnergyService* service = controller.createServiceObject(uuid, this); | ||
if (service) { | if (service) { | ||
connectServiceSignals(service); | connectServiceSignals(service); | ||
| 1,046行目: | 1,337行目: | ||
emit errorOccurred(errorMessage); | emit errorOccurred(errorMessage); | ||
if (autoReconnect && error != QLowEnergyController::InvalidBluetoothAdapterError) reconnectTimer | if (autoReconnect && error != QLowEnergyController::InvalidBluetoothAdapterError) reconnectTimer.start(); | ||
} | } | ||
| 1,059行目: | 1,350行目: | ||
if (autoReconnect && currentDevice.isValid()) { | if (autoReconnect && currentDevice.isValid()) { | ||
qDebug() << "再接続を試行..."; | qDebug() << "再接続を試行..."; | ||
controller | controller.connectToDevice(); | ||
} | } | ||
} | } | ||
| 1,314行目: | 1,605行目: | ||
<br><br> | <br><br> | ||
== BLE通信の使用例 == | |||
<syntaxhighlight lang="c++"> | |||
// BLEManager.hファイル | |||
#include <QCoreApplication> | |||
#include <QTimer> | |||
#include <memory> | |||
#include "bledevicescanner.h" | |||
#include "bleservicediscovery.h" | |||
#include "blepairing.h" | |||
#include "bleconnection.h" | |||
#include "bledatatransfer.h" | |||
class BLEManager : public QObject | |||
{ | |||
Q_OBJECT | |||
private: | |||
std::unique_ptr<BLEDeviceScanner> scanner; | |||
std::unique_ptr<BLEServiceDiscovery> serviceDiscovery; | |||
std::unique_ptr<BLEPairing> pairing; | |||
std::unique_ptr<BLEConnection> connection; | |||
std::unique_ptr<BLEDataTransfer> dataTransfer; | |||
QBluetoothDeviceInfo targetDevice; | |||
std::unique_ptr<QTimer> transferTimer; | |||
void connectSignals() | |||
{ | |||
// スキャナのシグナル接続 | |||
connect(scanner.get(), &BLEDeviceScanner::deviceDiscovered, this, &BLEManager::onDeviceDiscovered); | |||
connect(scanner.get(), &BLEDeviceScanner::errorOccurred, this, &BLEManager::onErrorOccurred); | |||
// ペアリングのシグナル接続 | |||
connect(pairing.get(), &BLEPairing::pairingComplete, this, &BLEManager::onPairingComplete); | |||
connect(pairing.get(), &BLEPairing::errorOccurred, this, &BLEManager::onErrorOccurred); | |||
// 接続管理のシグナル接続 | |||
connect(connection.get(), &BLEConnection::connected, this, &BLEManager::onConnected); | |||
connect(connection.get(), &BLEConnection::serviceDiscovered, this, &BLEManager::onServiceDiscovered); | |||
connect(connection.get(), &BLEConnection::errorOccurred, this, &BLEManager::onErrorOccurred); | |||
// データ転送のシグナル接続 | |||
connect(dataTransfer.get(), &BLEDataTransfer::characteristicChanged, this, &BLEManager::onCharacteristicChanged); | |||
connect(dataTransfer.get(), &BLEDataTransfer::errorOccurred, this, &BLEManager::onErrorOccurred); | |||
} | |||
void startPeriodicDataTransfer() | |||
{ | |||
transferTimer = std::make_unique<QTimer>(this); | |||
transferTimer->setInterval(1000); // 1秒間隔 | |||
connect(transferTimer.get(), &QTimer::timeout, this, [this]() { | |||
// サンプルデータの送信 | |||
QByteArray data = generateSampleData(); | |||
dataTransfer->writeCharacteristic(QBluetoothUuid(QString("YOUR_CHARACTERISTIC_UUID")), data ); | |||
}); | |||
transferTimer->start(); | |||
} | |||
QByteArray generateSampleData() | |||
{ | |||
// サンプルデータの生成 (実務では、適切なデータを生成) | |||
QByteArray data; | |||
data.append(0x01); // コマンド | |||
data.append(0x02); // データ長 | |||
data.append(0x03); // データ1 | |||
data.append(0x04); // データ2 | |||
return data; | |||
} | |||
void processReceivedData(const QByteArray &data) | |||
{ | |||
// 受信データの処理 (実務では、適切な処理を実装) | |||
if (data.isEmpty()) return; | |||
// データの解析例 | |||
quint8 command = data.at(0); | |||
switch (command) { | |||
case 0x01: | |||
qDebug() << "コマンド1を受信"; | |||
break; | |||
case 0x02: | |||
qDebug() << "コマンド2を受信"; | |||
break; | |||
default: | |||
qDebug() << "不明なコマンド: " << command; | |||
break; | |||
} | |||
} | |||
public: | |||
explicit BLEManager(QObject* parent = nullptr) : QObject(parent) | |||
{ | |||
// 各コンポーネントの初期化 | |||
scanner = std::make_unique<BLEDeviceScanner>(this); | |||
serviceDiscovery = std::make_unique<BLEServiceDiscovery>(this); | |||
pairing = std::make_unique<BLEPairing>(this); | |||
connection = std::make_unique<BLEConnection>(this); | |||
dataTransfer = std::make_unique<BLEDataTransfer>(this); | |||
connectSignals(); | |||
} | |||
// デバイススキャンを開始 | |||
void startDeviceScan() | |||
{ | |||
qDebug() << "BLEデバイスのスキャンを開始..."; | |||
scanner->startScan(); | |||
} | |||
private slots: | |||
void onDeviceDiscovered(const QBluetoothDeviceInfo& device) | |||
{ | |||
// ターゲットデバイスかどうかを確認 (実務では、適切なフィルタリングが必要) | |||
if (device.name().contains("YourDeviceName", Qt::CaseInsensitive)) | |||
{ | |||
scanner->stopScan(); | |||
targetDevice = device; | |||
qDebug() << "ターゲットデバイスを発見: " << device.name(); | |||
// ペアリングを開始 | |||
pairing->requestPairing(device.address()); | |||
} | |||
} | |||
void onPairingComplete(const QBluetoothAddress &address, bool success) | |||
{ | |||
if (success) { | |||
qDebug() << "ペアリング完了: 接続を開始..."; | |||
connection->connectToDevice(targetDevice); | |||
} | |||
else { | |||
qDebug() << "ペアリングに失敗"; | |||
} | |||
} | |||
void onConnected() | |||
{ | |||
qDebug() << "デバイスに接続完了"; | |||
connection->setAutoReconnect(true); // 自動再接続を有効化 | |||
} | |||
void onServiceDiscovered(QLowEnergyService *service) | |||
{ | |||
qDebug() << "サービスを発見: " << service->serviceUuid().toString(); | |||
// 対象のサービスかどうかを確認 | |||
if (service->serviceUuid() == QBluetoothUuid(QString("YOUR_SERVICE_UUID"))) { | |||
dataTransfer->setService(service); | |||
// Notifyを有効化 | |||
dataTransfer->enableNotifications(QBluetoothUuid(QString("YOUR_CHARACTERISTIC_UUID"))); | |||
// 定期的なデータ送信を開始 | |||
startPeriodicDataTransfer(); | |||
} | |||
} | |||
void onCharacteristicChanged(const QBluetoothUuid &uuid, const QByteArray &value) | |||
{ | |||
qDebug() << "データを受信:"; | |||
qDebug() << " UUID: " << uuid.toString(); | |||
qDebug() << " 値: " << value.toHex(); | |||
// 受信データの処理 | |||
processReceivedData(value); | |||
} | |||
void onErrorOccurred(const QString &error) | |||
{ | |||
qDebug() << "エラーが発生: " << error; | |||
// エラーに応じた適切な処理を実装 | |||
// ...略 | |||
} | |||
}; | |||
</syntaxhighlight> | |||
<br> | |||
<syntaxhighlight lang="c++"> | |||
// main.cppファイル | |||
#include <QCoreApplication> | |||
#include "BLEManager.h" | |||
int main(int argc, char *argv[]) | |||
{ | |||
QCoreApplication app(argc, argv); | |||
try { | |||
// BLEマネージャーオブジェクトの生成と開始 | |||
auto bleManager = std::make_unique<BLEManager>(); | |||
bleManager->startDeviceScan(); | |||
return app.exec(); | |||
} | |||
catch (const std::exception &e) { | |||
qDebug() << "致命的なエラーが発生: " << e.what(); | |||
return -1; | |||
} | |||
} | |||
</syntaxhighlight> | |||
<br><br> | |||
{{#seo: | {{#seo: | ||