Bluez & DBusでのアドバタイズパケットの受信に時間がかかるのでBLEスニファで調査をした (未解決)

# はじめに
今までSwitchBotのアドバタイズパケットを解析してデータをMQTTでPublishするプログラムをRaspberryPi向けに作っていた
最近人感センサーのパケットを解析できるように拡張したのだが、どうもセンサーが反応してからPublishまでに時間がかかっている(15から20秒ほど)ので原因を調査した

# プログラムの最適化
## Publish回数の削減
* 今のプログラムはアドバタイズパケットが来たらすべてPublishをしていた
* しかしPublish自体のオーバーヘッドが大きいため、前回のデータから更新がなければPublishしないように変更した

```cpp
std::vector<MqttMessage> MotionSensorDataHandler::createPublishMessages(const std::vector<uint8_t>& data)
{
    static uint16_t last_pir=0U;
  // :
        // Check if the PIR time has changes
        if(pir_time < last_pir)
        {
            std::string pir_time_str = "Since the last trigger PIR time (s): " + std::to_string(pir_time);
            mosquitto_property* properties = nullptr;
            MqttMessage pir_time_message{pir_time_topic_str, pir_time_str,0,false,properties};
            messages.emplace_back(pir_time_message);
        }
        last_pir = pir_time;
```

## DBusメッセージの再利用
* また、従来は毎ループごとにアドバタイズパケットを取得するDBusメッセージを作成していたので、センサ毎にメッセージを前もって作成し、保存しておくようにした
* メッセージはunique_ptrとして保持し、デリータでdbus_message_unrefを呼ぶようにすることで確実に解放されるようにした

```cpp
struct DBusDeleter
{
    void operator()(DBusMessage* msg) const
    {
        if (msg)
        {
            dbus_message_unref(msg);
        }
    }
};

// Create messages in advance
void BluezAbstructLayer::createDbusMessages()
{
    for(auto itr : m_sensorDataHandlers)
    {
        std::string device_path = m_crate_device_path(itr->get_device_mac());
        DBusMessage* msg = dbus_message_new_method_call(BLUEZ_SERVICE.c_str(), device_path.c_str(), DBUS_PROPERTIES.c_str(), METHOD_GET_ALL.c_str());
        if (!msg) {
            std::cerr << "Failed to create DBus message\n";
            return;
        }
        const char* interface_name = BLUEZ_DEVICE.c_str();
        dbus_message_append_args(msg, DBUS_TYPE_STRING, &interface_name, DBUS_TYPE_INVALID);

        std::unique_ptr<DBusMessage, DBusDeleter> uMsg(msg);
        m_dbus_messages.push_back({std::move(uMsg), itr});
    }
}
```

しかし、以上の改善を行ってもセンサの値がPublishされるまでの時間に改善はなかった

# BLEをスニフする
家にBLEスニファが転がっていたので実際どのようにアドバタイズパケットが発信されているのかを調べることにした

https://www.switch-science.com/products/3347?srsltid=AfmBOoqiXNLNEmikKf-rMqhKwXPd22lus7JJ7WXYPdEbYg4yqXIRJPHj

以下のサイトを参考にWiresharkにBLEスニファのプラグインを追加し、パケットをキャプチャした

https://tech-blog.abeja.asia/entry/advent-2024-day14

取得したパケットには当然環境中のいろいろなBLEパケットが含まれているのでフィルタする必要がある
* 今回調べたいセンサのMACアドレスからのパケットを抽出し、さらに大量に表示されているADV_IND(PDU type: 0x00)を除外してSCAN_RESP(人感センサの値が入っている)を見やすいようにしたい

このサイトにフィルタの一覧があるので、参考にして以下のようにフィルタを設定した

```btle.advertising_address == <mac> and btle.advertising_header.pdu_type!=0x00```

https://www.wireshark.org/docs/dfref/b/btle.html


結果は以下のようになった
* Raspberry PiからのSCAN_REQの数に対してSCAN_RESPの数が多いように見えるが、理由はわからない

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/296478/93c9fbf9-0793-4a12-802a-0d06c2b7658a.png)

SCAN_RESPの各パケットからPIR時間を抽出してプロットすると以下のようになった
動きに変化があった40秒付近にSCAN_RESPが集中しているが、大体5秒間に1回か最低でも10秒に1回はSCAN_RESPが発信されていそうだ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/296478/1f764d93-56cb-40ab-98af-77747d4a1f28.png)

そうなるとやはりRaspberryPi側にボトルネックがあることになるので、Bluez・DBusの使い方やプログラムのロジックのさらなる見直しをしていきたい
* ちなみにChatGPT 4oに相談したところ、DBusのPropertyの変更をリッスンしたほうがいいといわれたのでサンプルコードを作って試してみた
* 結果は何も変わらなかったが、それがアプローチの筋が悪いのか吐き出したサンプルコードが悪いのかが判断つかないので、やはり勉強は自分で考えないと意味がないなと思った