
81. Device Streams を試す
はじめに
Azure IoT Operations 、そろそろ試そうかなぁ、でもまだプレビューだしぃ…等と思いつつ、今回は、Azure IoT Hub の一機能として公開されて永らくずっとプレビュー状態の Device Streams を試してみることにします。
この機能、俺好きだぜって感じの機能で、正式公開になったらこの定期購読マガジンで取り上げようと思っていたのですが、ずっとそのままなので、業を煮やしました。
セキュアでイケてる機能なんですけどね…
最初に誤っておく ~ 中途半端な記事で申し訳ないです
…すいません、最初にぶっちゃけておきます。昔々、多分5年前ぐらいの2019年あたりに実際にこの機能を使って、リモート接続実際にやっていたのですが、今は、もう Device Streams は使えないようです。
Azure IoT Hub デバイス ストリーム | Microsoft Learn
という、Microsoft Learn の記事、更新日時が 2023/6/1 なので、まだ機能しているのかと思って試そうとしましたが駄目でした。今回は、それが判るまでの顛末の記事です。ご了承くださいませ。
使えないなら、削除したほうがいいと思うよ、マイクロソフトさん
※ 2024/3/20 時点で書いた記事です
Device Streams
Device Streams は、Azure IoT Hub の一機能です。どんな機能かというと、IoT 機器を IoT Device として Azure IoT Hub に登録して、Azure IoT Hub に接続すると、その接続を通じて、IoT 機器と、サービス側から Azure IoT Hub に接続したサービスロジックを、TCP トンネル接続してくれるというイケてるフィーチャーです。

TCP トンネルを作ってくれるので、IoT 機器と Azure IoT Hub との間のセキュリティと、Azure IoT Hub とサービスロジックとの間のセキュリティ設定だけで、IoT 機器とサービスロジックの間で、SSH 接続や RDP 接続が可能になります。IoT 機器が Linux 系でも Windows 系でも動きます。
これ、凄くない?
結構前に、これを試したことがあって、
SSH で接続する= サービスロジック側のコンピューターノード上で、IoT 機器にリモートシェル接続して、root 権限で色々いじくりたおす
RDP で接続する= IoT 機器の Windows のデスクトップをサービスロジック側のコンピュータノード上で表示し操作する
という事が実際にできてました。多分、RTSP 接続(実はこれが一番やりたい事)もできるんじゃないかと思ってます。
接続手順
図の順番に接続や許可を行っていくと、諸々凄いことができます。

IoT 機器がコールバックを登録
サービスロジックの Device Streams の利用開始
IoT 機器が登録したコールバックをコール
IoT 機器に Device Streams 接続用のエンドポイントを通知
サービスロジックに Device Streams 接続用のエンドポイントを通知
という手順を経て、Device Streams による接続が可能になります。3番目で、IoT 機器は、接続の拒否を行う事も出来ます。
試してみる
では、早速試していく事にします。
Azure IoT Hub の制限
…と、”接続の要件”に記載の

”Device Streams Endpoint” が、前から利用している Azure IoT Hub の概要ページに表示されてない!
はい、このフィーチャー、まだプレビューなので、限定されたリージョンでしか、現在使えません。”リージョン別の提供状況”によれば、2024/3/20 現在、
米国中部、米国東部 EUAP、北ヨーロッパ、東南アジア
でしか使えないとのこと。なので、そのリージョンで作成することにします。

今回は、”North Europe” で作成してみました。スケール設定は”無料”でも使えるようです。
IoT 機器、及び、Azure IoT Hub への IoT Device 登録
次は、Azure IoT Hub に Device Streams で接続する IoT 機器の名前を IoT Device として登録します。

名前は、”raspberrypi-taruto”としました。対象キー接続のままで登録を終えます。
Azure IoT Hub の準備が終わったので、IoT 機器、サービスのコード作成に移ります。Microsoft Learn のドキュメントには、具体的なコードが一切載せられていません。不親切だなぁ…
探してみると、
当たりのサンプルコードが見つかりました。ちなみに、Bing Copilot はこれを見つけられなかったぁ…
気を取り直して、これらのサンプルを参考にコードを組んでいく事にします。
IoT 機器側のコード
IoT 機器は、Raspberry Pi を使う事にします。
プログラムは、.NET Framework を使い、C# で記述します。
Visual Studio 2022 でコンソールアプリケーションを ConsoleAppDeviceStreamsProxy という名前で作成します。
Device Streams を使うには、一般的な Azure IoT Hub に IoT 機器を接続通信する際に使うのと同じ、Azure IoT Device SDK を利用します。
なので、コンソールアプリケーションプロジェクトを作成したら、NuGet で Microsoft.Azure.Devices.Client パッケージをインストールします。
ここまでのやり方は、過去のこの定期購読マガジンの記事から探してみてくださいね。
参照しているサンプルに、コンソールアプリケーション用のログ出力パッケージが使われているので、それも、ちゃっかり頂き、Microsoft.Extentions.Logging.Console パッケージもインストールしておきます。
はい。ここまではサクサク来ましたが、ここから先には進めませんでした。

時系列的に正確に書くと、GitHub - fzankl/iot-hub-devicestreams-sample: Example how to work with Azure IoT Hub Device Streams に書かれているコードで最初に出ちゃったのは、DeviceClient にWaitForDeviceStreamRequestAsync method がないというエラー。
Microsoft.Azure.Devices.Client のバージョン
The method WaitForDeviceStreamRequestAsync doesn't exists · Issue #81450 · MicrosoftDocs/azure-docs · GitHub によれば、Device Streams の機能は、特定のごく一部のバージョンの Azure IoT Device SDK for C# にしか入っていないとのことでした。2024/3/20 時点での Microsoft.Azure.Devices.Client の最新バージョンは、2023/12/21 にリリースされた 1.42.2 ですが、どうやら、1.29.0-preview-0.0.x あたりを使えとのこと。
とりあえず、一通り試してみました。WaitForDeviceStreamRequestAsync が存在するのは、
1.29.0-preview-0.0.1
1.29.0-preview-0.0.2
1.29.0-preview-0.0.4
1.29.1-preview-0.0.1
1.29.1-preview-0.0.2
1.29.1-preview-0.0.3
1.32.0-preview-0.0.1
でした。どうやっているかというと、地道に、

こんな風にインストールしたいバージョンをコンボボックスで選択して”更新”ボタンをクリックするという作業です。
一応、WaitForDeviceStreamRequestAsync とAcceptDeviceStreamRequestAsync の二つは存在するパッケージのバージョンを見つけられたのですが、iot-hub-devicestreams-sample/src/DeviceProxy/DeviceStream.cs at master · fzankl/iot-hub-devicestreams-sample · GitHub で使われている DeviceStreamClientFactory が存在するパッケージはどうしても見つけられませんでした。
とほほ
Azure IoT Device SDK for C# の github のリポジトリーのリリースを確認すると、
Releases · Azure/azure-iot-sdk-csharp (github.com)
あたりで、Visual Studio 2022 の NuGet 管理 GUI では出てこない、もっと細かい Preview 用パッケージ(例えば、1.27.1-preview-001 とか)がリリースされていました。5年ぐらい前に使ったのは、その辺りのパッケージだったのでしょうか?多分その当時は、そのバージョンのサンプルコードとして、ちゃんと動くコード一式があったのかもしれません。
この古い SDK のコードセットを使えば、動くものが再現できるのかもしれませんし、IoT Hub の REST API を使えば、まだ対応できるのかもしれませんが、どうせ、長期にわたって正式リリースにならなかったフィーチャーなので、大変申し訳ないのですが、ここで潔くあきらめることにします。
ごめんなさい🙇
本当は、Device Streams で、 ローカルな動画ストリームを RTSP で、サーバーサイドから、試聴したかったんだけどね…涙
何故、正式リリースに至らなかったんだろう…
今回、途中で放り出すという情けない結果になってしまったのですが、でも、機能的には、凄っく便利な機能なのは間違いないと思いませんか?
IoT 機器と Azure IoT Hub 間の接続、及び、サービスロジックと Azure IoT Hub 間の接続のセキュリティだけ使って、SSH や RDP 等の TCP プロトコルをトンネル出来る機能が消えてしまうのは、重ね重ね、残念です。
しかし、色んなプロトコルが使えるという事は、それぞれのユーザーによって、ユースケースシナリオがバラエティに富む、という事を意味し、その際に発生するデータ転送量や処理量も千差万別になる事も意味します。
こういうサービスの QoS を定義するのは難しいんでしょうね。
また、万が一、Azure IoT Hub にアクセスする為の対象キー(主にサービス側か?)が万が一、人的ミスで悪意のある第三者に漏れてしまった場合、かなり危険なのは間違いないですね。まぁ、IoT 機器側で接続を許可・拒絶が出来るので、二要素認証等とも合わせれば、ある程度脅威は抑えられるような気もしますが。
まぁ、そんなリスクも負いつつ、絶対にこれ使いたいという、大口ユーザーがいなかったというのが、一番の要因でしょうかね。
元マイクロソフト社員の私見ですがw
おまけ
これで終わってしまうのは、有料読者に申し訳ないので、コンソールアプリケーションのロギング機構について書いておきます。
コンソールアプリの場合、System.Console クラスの WriteLine method で、コマンドシェルの標準出力(C言語なら stdout)に出力が可能です。
でもこれ、コマンドシェルがあれば、出力結果を見ることができますが、76回目の記事で試したような、シェル無しのサービス実行の場合は、見ることができません。そんな時は、前述の、Microsoft.Extentions.Logging.Console パッケージを使うと、便利。
C# でのログ記録 - .NET | Microsoft Learn
それぞれの機能モジュールを実装する class に Microsoft.Extensions.Logging.ILogger という class のプロパティを定義し、
public class Foo
{
private ILogger logger;
...
public Foo(..., ILogger logger)
{
...
this.logger = logger
}
public async Task DoSome(...)
{
// 通常のログ
logger.LogInformation(...);
// 警告のログ
logger.LogWarning(...);
// エラーのログ
logger.LogError(...);
}
}
てな感じでログを残しておきます。
logger インスタンスの作成については、コンソールアプリなら、例えば、
using Microsoft.Extensions.Logging;
using var loggerFactory = LoggerFactory.Create(static builder =>
{
builder
.AddFilter("Microsoft", LogLevel.Warning)
.AddFilter("System", LogLevel.Warning)
.AddFilter("ConsoleAppDeviceStreamsProxy.Program", LogLevel.Debug)
.AddConsole();
});
ILogger logger = loggerFactory.CreateLogger<Program>();
logger.LogDebug("Hello {Target}", "Everyone");
こんな感じ。
最後に
超絶中途半端な記事で大変申し訳ないです。
ただ、参考になりそうなポイントは幾つか散りばめたはずなので、その辺でお許しを
ここから先は
Azure の最新機能で IoT を改めてやってみる
2022年3月にマイクロソフトの中の人から外の人になった Embedded D. George が、現時点で持っている知識に加えて、頻繁に…
この記事が気に入ったらチップで応援してみませんか?