AITRIOS Local EditionをLocal Console以外で推論開始し受信する

# 1. はじめに
AITRIOS LocalEditionでは推論開始・終了の操作と推論結果の受信にLocalConsoleが必要です。
学習モデルの確認であれば問題ないのですが、いよいよ実際の環境で運用する際にはこれでは不便なので、**Local Console以外のアプリケーションで推論開始・終了の操作と推論結果を受信する方法**を実際の調査過程とともに紹介します。

なお、調査にはAITRIOS LocalEdition 1.4.0.aと[AIH-IVRW2](https://www.aitrios.sony-semicon.com/edge-ai-devices)（AITRIOSのエッジカメラ）を使用し、AIH-IVRW2のFWのバージョンは以下の通りです。

Main chip	: 0400FEWS
Sensor Chip FW (main)	: 020300
Sensor Chip FW (loader)	: 020301

また、[Wireshark](https://www.wireshark.org/)を使用して通信パケットのキャプチャも行っています。

調査にあたっては、@matsujirushi さんからXにて多大なアドバイスをいただきました。ありがとうございます。

# 2. Mosquittoの設定変更

AITRIOS LocalEditionをインストールすると自動的にMQTTブローカーの[Mosquitto](https://mosquitto.org/)もインストールされますが、初期状態では外部からの接続ができない状態になっています。
LocalEditionの起動時にはバックグラウンドでは外部接続が可能な状態でmosquittoが立ち上がるようですが、ここではmosquittoの初期状態を外部接続が可能な状態に設定します。

Windowsではサービスの一覧画面から```Mosquitto Broker```を探し出し、起動していれば一旦停止します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/360166/c3d6807b-e027-416a-a8cb-2668046b39d7.png)

次に、Mosquittoインストール先の```mosquitto.conf```ファイルを編集します。
windowsであればファイルまでのパスは```C:\Program Files\mosquitto\mosquitto.conf```です。
もし上書き禁止になっていたら、アクセス権の設定を変更してログインユーザーでも変更できるようにしましょう。

```mosquitto.conf```ファイルに追記する内容は以下の2行です。ファイルの最後にでも追記しましょう。
それぞれ、MQTTブローカーのポートとユーザー名を指定しない接続を許可する旨の設定です。

```txt:mosquitto.conf
listener 1883
allow_anonymous true
```

```mosquitto.conf```ファイルに追記できたら、サービス一覧の画面から開始を選択してMosquittoを再起動させます。

スタートアップの種類が自動であれば、PCを再起動した際に今回の設定が反映された状態で自動的にMosquittoが起動するはずです。

# 3. MQTTによる推論開始・終了メッセージ

## 3-1. Wiresharkを使用して確認

まずはAIH-IVRW2と、LocalConsoleをセットアップしたPC間の通信内容を確認する必要があります。


WiresharkでPCのネットワーク接続に対し```ip.addr == <AIH-IVRW2のIPアドレス>```をフィルタに設定すると、このようにAIH-IVRW2から送受信された通信パケットがフィルタリングされた状態で表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/360166/d030b4de-7f1c-453a-9559-8efeb6386893.png)

※AIH-IVRW2のIPアドレスはWi-Fiルーターから探し出すか、Wi-Fi接続時の設定でIPアドレスを固定IPにしてください。
クライアント名は```nuttx```です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/360166/e1d88645-4569-468f-8cfd-944cbf61bd30.png)

この状態でLocal Consoleにて推論開始のボタンを押します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/360166/e0ce5635-3235-40da-83bd-696678461b90.png)

すると、この瞬間にMQTTで```Publish Message```から始めるMQTTのメッセージがPCからAIH-IVRW2へPublishされるのが観測できます。
**これが推論開始のメッセージです**。
※MQTTのポート番号はWi-Fi接続用のQRコード作成時に設定したポートになっているはずです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/360166/2b132a3c-770b-4c2f-ade5-5b1884bc7471.png)

送信パケット詳細ウインドウを開いて一番下の部分に```Message```があり、これがMQTTでAIH-IVRW2へ向けてPublishされたJSON形式のメッセージです。
Messageの部分は右クリックして```コピー→ASCII形式テキストとして…```を選択すると、文字列としてコピーでき、[JSONきれい ～JSON整形ツール～](https://tools.m-bsys.com/dev_tools/json-beautifier.php)などで見やすくした状態にできます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/360166/d2937f87-9f31-474a-8200-b7347d871607.png)

実際の推論開始のJSON形式のメッセージは以下の通りです。
```json:推論開始
{
	"method": "ModuleMethodCall",
	"params": {
		"moduleMethod": "StartUploadInferenceData",
		"moduleInstance": "backdoor-EA_Main",
		"params": {
			"CropHOffset": 0,
			"CropVOffset": 0,
			"CropHSize": 4056,
			"CropVSize": 3040,
			"Mode": 1,
			"UploadMethod": "HttpStorage",
			"StorageName": "http://<httpサーバのIPアドレス>:<ポート番号>",
			"StorageSubDirectoryPath": "images",
			"UploadMethodIR": "HttpStorage",
			"StorageNameIR": "http://<httpサーバのIPアドレス>:<ポート番号>",
			"UploadInterval": 30,
			"StorageSubDirectoryPathIR": "inferences"
		}
	}
}
```

併せて推論停止のJSONメッセージも紹介しておきます。
```json:推論停止
{
	"method": "ModuleMethodCall",
	"params": {
		"moduleMethod": "StopUploadInferenceData",
		"moduleInstance": "backdoor-EA_Main",
		"params": {}
	}
}
```

推論せずに撮影のみの場合は推論開始のJSONメッセージとほぼ同じですが、```Mode```のパラメータを0にします。
```json:撮影のみ
{
	"method": "ModuleMethodCall",
	"params": {
		"moduleMethod": "StartUploadInferenceData",
		"moduleInstance": "backdoor-EA_Main",
		"params": {
			"CropHOffset": 0,
			"CropVOffset": 0,
			"CropHSize": 4056,
			"CropVSize": 3040,
			"Mode": 0,
			"UploadMethod": "HttpStorage",
			"StorageName": "http://<httpサーバのIPアドレス>:<ポート番号>",
			"StorageSubDirectoryPath": "images",
			"UploadMethodIR": "HttpStorage",
			"StorageNameIR": "http://<httpサーバのIPアドレス>:<ポート番号>",
			"UploadInterval": 30,
			"StorageSubDirectoryPathIR": "inferences"
		}
	}
}
```

なお、このメッセージは[Console ユーザーマニュアルのCommand Parameterファイル (JSON) 仕様](https://developer.aitrios.sony-semicon.com/edge-ai-sensing/documents/console-user-manual?version=2025-02-03&progLang=#_startuploadinferencedata)に概ね準拠しています。
なので、設定内容を変更したいときには参考になるはずです。

大事なのは```StorageName```と```StorageNameIR```で、このパラメータでメタデータと画像データの送信先を設定しています。
**このパラメータはLocalConsoleではポート番号をランダムに設定している**ので、LocalConsoleやAIH-IVRW2では一意に決めていません。
逆に言えば、**LocalConsole以外のアプリケーションからMQTTでこのフォーマットに沿ったメッセージをPublishすれば、自前で構えたhttpサーバに対してデータを送るように指示できる**ということです。


## 3-2. Pythonで推論開始・終了メッセージをPublish

では実際に推論開始・停止のメッセージをMQTTでPublishしてみます。

下記のプログラムを実行すると推論開始のメッセージをPublishできます。
なお、```paho-mqtt```ライブラリが必要になるので、あらかじめ```pip install paho-mqtt```でインストールしておいてください。

```python:python
import json
import paho.mqtt.client as mqtt

# MQTT Brokerの設定
broker = "localhost"  # MQTT Brokerのホスト（適宜変更）
port = 1883           # MQTT Brokerのポート（適宜変更）
topic = "v1/devices/me/rpc/request/26255775"

# 送信するメッセージ
message = {
	"method": "ModuleMethodCall",
	"params": {
		"moduleMethod": "StartUploadInferenceData",
		"moduleInstance": "backdoor-EA_Main",
		"params": {
			"CropHOffset": 0,
			"CropVOffset": 0,
			"CropHSize": 4056,
			"CropVSize": 3040,
			"Mode": 1,
			"UploadMethod": "HttpStorage",
			"StorageName": "http://192.168.11.100:62074",   # メタデータ送信先のhttpサーバ（適宜変更）
			"StorageSubDirectoryPath": "images",
			"UploadMethodIR": "HttpStorage",
    		"StorageNameIR": "http://192.168.11.100:62074", # 画像データ送信先のhttpサーバ（適宜変更）
			"UploadInterval": 30,
			"StorageSubDirectoryPathIR": "inferences"
		}
	}
}
# メッセージをJSON形式に変換
message_json = json.dumps(message)

# MQTTクライアントの設定
client = mqtt.Client()

# MQTT Brokerへの接続
client.connect(broker, port)

# メッセージの送信
client.publish(topic, message_json)

# メッセージ送信後に接続を切断
client.disconnect()

print(f"Message sent to topic {topic}")
```

MQTTでメッセージをPublishするには相手先をTopicで指定する必要があります。
上で紹介しているWiresharkで捕まえた推論開始のメッセージからは、Topicが```v1/devices/me/rpc/request/26255775```であると読み取れるのですが、図中にも書いているように8桁の数字はランダムな数字であればなんでもいいようで、繰り返しの使用も可能でした。
ただし、**推論開始と推論停止では別の8桁の数字にしないとメッセージを受け取ってくれない**ようです。


# 4. httpによる推論結果のメタデータと画像データの受信

## 4-1. Wiresharkを使用して確認

[3-2. Pythonで推論開始・終了メッセージをPublish](#3-2-Pythonで推論開始・終了メッセージをPublish)で作成した推論開始のフローを実行すると、AIH-IVRW2から指定したIP・ポートに向けてhttpで推論結果のメタデータと画像データが送信されてきます。
これもWiresharkを使用して確認します。

AIH-IVRW2からは先に画像データの方が送信されてきます。
下記スクリーンショットの```put /images/****.jpg```のデータがそうです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/360166/c330f437-55da-418f-bba2-84e6011f7027.png)

画像データは~~BASE64形式でエンコードされた文字列~~バイナリデータとして送信されてくるので、スクリーンショットのようにBASE64形式でコピーして https://rakko.tools/tools/71/ などでデコードするとjpg画像として確認できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/360166/827f1dd0-0eb0-416f-b13e-2d2c04db2efa.png)

推論結果のメタデータの方は同じくhttpプロトコルの```PUT /inferences/****.txt```のデータです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/360166/69d38aa1-7cd8-4233-bf8b-92f14356849b.png)

スクリーンショット左下のDataで選択し反転した範囲がデシリアライズ前の推論結果のJSONデータなので、ASCII形式でコピーしテキストファイルとしてコピーしたうえで下記の記事で紹介している**推論結果をデシリアライズするPythonコードの作成・実行**を行えば、JSON形式に変換できます。

https://qiita.com/todateman/items/7df96dfef14f8840d1bc#4-%E6%8E%A8%E8%AB%96%E7%B5%90%E6%9E%9C%E3%82%92%E3%83%87%E3%82%B7%E3%83%AA%E3%82%A2%E3%83%A9%E3%82%A4%E3%82%BA%E3%81%99%E3%82%8Bpython%E3%82%B3%E3%83%BC%E3%83%89%E3%81%AE%E4%BD%9C%E6%88%90%E5%AE%9F%E8%A1%8C

# 4-2. Pythonプログラムで受信用サーバを構築

AITRIOS公式の[外部転送設定チュートリアル (HTTP Server)](https://developer.aitrios.sony-semicon.com/edge-ai-sensing/documents/external-transfer-settings-tutorial-for-http-server?version=2025-02-03&progLang=#_http_server_%E3%82%BB%E3%83%83%E3%83%88%E3%82%A2%E3%83%83%E3%83%97)にPythonで推論結果のメタデータ・画像データ受信用のHTTPサーバセットアップ方法が紹介されています。
```5. HTTP Server セットアップ```を実行すると、**LocalConsole以外で推論結果のメタデータ・画像データを受け取ることができます。**

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/360166/4a419d36-1a56-426e-8deb-29d26465c01e.png)

# 5. おわりに

LocalEdition購入時からずっと気になっていたLocalConsoleを使用しない推論実行・推論結果の受信方法をようやく明らかにすることができました。

自分の所属する会社もそうですが、クラウドの利用や従量課金制の支払いに対して制約のある会社は一定数あると思いますので、プリペイドで支払いができLocal環境で完結するLocalEditionを使用してのAITRIOSの利用を検討している方の参考になれば幸いです。