MQTTv5のプロパティ(property)を、mosquittoとAWS IoT Coreで使う

MQTTv5には、プロパティが実装されました。
プロパティとは、データ本体(ペイロード)を修飾する情報です。HTTPのヘッダのような位置づけになります。AWS IoT Core(以下、IoT Core) は [MQTTv5 に対応](https://aws.amazon.com/blogs/iot/introducing-new-mqttv5-features-for-aws-iot-core-to-help-build-flexible-architecture-patterns/)しており、プロパティを扱うことができます。

MQTTv5のプロパティ(property)を、[Eclipse Mosquitto](https://mosquitto.org/)と[AWS IoT Core](https://aws.amazon.com/jp/iot-core/)で使ってみました。

## MQTTv5 のプロパティ

MQTTv5 のプロパティには、MQTTv5で既定されたプロパティと、ユーザーが自由に設定できるプロパティ(ユーザープロパティ)の２種類があります。

既定プロパティには、ペイロードのフォーマットを表す "Content Type" や、サブスクライブ側での処理結果を返して欲しいトピックを示唆する "Response Topic" といったものがあります。ユーザープロパティはキー名と値を指定します。
既定プロパティについては [MQTTv5 properties](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901027) や [mosquitto の properties](https://mosquitto.org/man/mosquitto_pub-1.html#properties) をご覧ください。

## AWS IoT Core を MQTT ブローカー(サーバー)として、クライアント間でプロパティを扱う

IoT Coreは MQTTブローカー(サーバー)として動作します。ここではIoT Coreに接続した2つのMQTTクライアント間で、トピック `my/topic` に、データ= `{"v1":1}` と共に、ユーザープロパティ key = `KEY1` value = `VALUE1` を Publish/Subscribe の様子を見てみます。

:::note info
AWS IoT Core との通信は MQTTS(MQTT+TLS) です。暗号化通信に使う X.509 証明書は[AWS IoT クライアント証明書を作成する](https://docs.aws.amazon.com/ja_jp/iot/latest/developerguide/device-certs-create.html)で作成しています。
:::

```bash:Publish側
mosquitto_pub -V 5 -d -i a2 -h foobar-ats.iot.us-east-2.amazonaws.com -p 8883 \
--cafile AmazonRootCA1.pem --cert 99a6e4b-certificate.pem.crt --key 99a6e4b-private.pem.key \
-t my/topic -m '{"v1":1}' --property PUBLISH user-property KEY1 VALUE1
```

サブスクライブ側では以下の通りです。

```bash:Subscribe側
mosquitto_sub -V 5 -d -i a1 -h foobar-ats.iot.us-east-2.amazonaws.com -p 8883 \
--cafile AmazonRootCA1.pem --cert fb76055-certificate.pem.crt --key fb76055-private.pem.key \
-t my/topic -F "%j" --pretty
```

```json:受信時のデータ
{
        "tst":  "2022-12-16T23:27:57.854315Z+0900",
        "topic":        "my/topic",
        "qos":  0,
        "retain":       0,
        "payloadlen":   8,
        "properties":   {
                "user-properties":      {
                        "KEY1": "VALUE1"
                }
        },
        "payload":      "{\"v1\":1}"
}
```

データ本体である **payload** とは別に、**properties** がKey-Valueの形で受け取れています。

既定プロパティの "Response Topic" の指定時は以下の通りです。

```bash:Publish側
mosquitto_pub -V 5 -d -i a2 -h foobar-ats.iot.us-east-2.amazonaws.com -p 8883 \
--cafile AmazonRootCA1.pem --cert 99a6e4b-certificate.pem.crt --key 99a6e4b-private.pem.key \
-t my/topic -m '{"v1":1}' --property PUBLISH response-topic "foo/bar"
```

```bash:Subscribe側(コマンドライン自体は同じ)
mosquitto_sub -V 5 -d -i a1 -h foobar-ats.iot.us-east-2.amazonaws.com -p 8883 \
--cafile AmazonRootCA1.pem --cert fb76055-certificate.pem.crt --key fb76055-private.pem.key \
-t my/topic -F "%j" --pretty
```

```bash
{
        "tst":  "2022-12-16T23:27:53.983234Z+0900",
        "topic":        "my/topic",
        "qos":  0,
        "retain":       0,
        "payloadlen":   8,
        "properties":   {
                "response-topic":       "foo/bar"
        },
        "payload":      "{\"v1\":1}"
}
```

プロパティはあくまでも「ヒント」ですので、Content Type や Response Topic といったプロパティの値を採用するか否かは受信側の実装となります。

[AWSブログで紹介されている "Request/Response pattern"](https://aws.amazon.com/jp/blogs/iot/introducing-new-mqttv5-features-for-aws-iot-core-to-help-build-flexible-architecture-patterns/#:~:text=1.%20More%20transparent%20messaging%20with%20the%20Request/Response%20pattern) というのは、Response Topic を使ったパターンということになります。

## プロパティは AWS IoT Core のルール内で参照可能

プロパティは AWS IoT Core のルール内で参照できます。読み出しには2つの関数があります。

- [get_mqtt_property(name)](https://docs.aws.amazon.com/iot/latest/developerguide/iot-sql-functions.html#iot-sql-function-get-mqtt-property): `response-topic` 等、MQTTv5 の既定プロパティを読み出す
    - 例) `get_mqtt_property("response_topic")`
- [get_user_properties(userPropertyKey)](https://docs.aws.amazon.com/iot/latest/developerguide/iot-sql-functions.html#iot-sql-function-get-user-properties): `user-property` を対象に読み出す
    - 例) `get_user_properties("KEY1")`

AWSブログでは [Conetnt Type が Base64 だったら decode() 関数を通すという実装例](https://aws.amazon.com/jp/blogs/iot/introducing-new-mqttv5-features-for-aws-iot-core-to-help-build-flexible-architecture-patterns/#:~:text=Processing%20MQTT%20packets%20with%20user%20properties%20on%20AWS%20IoT%20Core%20topic%20rules)が紹介されています。

## おわりに

こういった「域外通信」には、以下のようにペイロード内に `_header` のような項目を入れて実装していたかと思いますが、これが無くせるというのは実装の見通しが良くなりそうですね。

```json:Payloadに全部押し込んでいるケース
{
  "data": "djE9MSx2Mj0iZm9vYmFyIgo=",
  "_header": {
    "content-type": "base64",
    "response-topic": "foo/bar"
  }
}
```

MQTTv5 はプロパティ以外にも、２回目以降のTopic指定文字列を削減できるトピックエイリアスといった実装に有利な機能が入っています。Eclipse Mosquittoも、[かなり率先して追従](https://mosquitto.org/blog/)してますので、まずはコマンドラインで試してみるのはいかがでしょうか。

EoT