コアMQTT

Things Cloud の Core MQTT 実装には、次の利点があります。

  • マルチテナントのサポート: 1 つのエンドポイントが複数のテナントに対応します。
  • デバイスID管理: デバイス固有の認証情報を使用してデバイスを認証します。
  • デバイス登録: カスタマイズしていない非パーソナライズなデバイスは、Things Cloud テナントとペアリングすることでご利用可能となります。
  • デバイス管理: 定義済みの豊富なデバイス管理ペイロード形式により、多数のデバイスを簡単に管理できます。
  • 標準IoTペイロード形式: IoT センサーの読み取り、アラーム管理、リモートコントロール、デバイス階層をサポートするために事前定義されたペイロード形式です。
  • カスタムペイロード形式: ペイロード形式を追加できます。
  • トラフィックオーバーヘッドを小さくできます。
  • 処理モード: データを Things Cloud データベースに保存する、リアルタイム処理に一時的に渡す、リアルタイム通知を無効化にする QUIESCENT モードを使用して処理する、リアルタイム通知が無効化された場合にのみデータをリアルタイム処理エンジンに一時的に送信する CEP モードを使用して処理する、のいずれかを制御します。
  • 完全な双方向通信が可能で、デバイス、サーバー間のメッセージを簡単に送受信できます。
  • Web ソケットのMQTT接続をサポートします。
  • TLS をサポートします。
  • 完全な水平方向の拡張性をサポートします。

Things Cloud プラットフォームの Core MQTT 機能により、デバイスが Core MQTT の事前定義されたトピックスキーマとペイロード形式を実装していれば、MQTT デバイスはメッセージを Things Cloud に直接送信できます。 特定の Things Cloud プロトコルをサポートしていない MQTT デバイスを統合するには、テナントがデバイスプロトコルと Things Cloud API の間のマッピングを実装する必要があります。 これは、Things Cloud の MQTT サービス と統合されたマイクロサービス、または外部の エージェント を使用して実行できます。

SmartREST ドキュメントも参照してください。

このドキュメントでは、MQTT 通信の基本については説明しません。 MQTT に慣れていない場合は、インターネット上にある数多くの入門資料のいずれかを参照することをお勧めします。 参考情報のいくつかは、MQTT Web サイト にあります。

備考
プラットフォームへのすべての Core MQTT 接続で許容される最大ペイロードサイズは 16184 バイト(16KiB)です。これには、メッセージヘッダーと本文の両方が含まれます。ヘッダーサイズはさまざまですが、最小サイズは 2 バイトです。

統合ライフサイクル

基本的なデバイスを Things Cloud に統合するライフサイクルについては、デバイスのインターフェース で説明されています。

このセクションでは、MQTT 実装を使用してこのライフサイクルを管理する方法を示します。

ライフサイクルは、スタートアップフェーズとサイクルフェーズの2つのフェーズで構成されています。

スタートアップフェーズ は、認証情報を確認するだけでも短くなる場合があります。

  • ステップ 0: デバイスの認証情報をリクエストします(まだ要求されていない場合)。
  • ステップ 1: デバイスが存在することを確認します。
  • ステップ 2: デバイスの子が存在することを確認します。
  • ステップ 3: トピックにサブスクライブします。

サイクルフェーズ は、2種類のアクションで構成されています。

MQTT フェーズ

必要条件
  • ブートストラップユーザー認証情報を介してアクセスします。ブートストラップ認証情報の取得と使用方法については、デバイスの認証情報 を参照してください。

スタートアップフェーズ

ステップ 0: デバイスの認証情報を要求する

Things Cloud では、すべての MQTT 接続は認証される必要があります。デバイスの認証情報を生成するために、MQTT 実装のデバイス認証情報トピックを使用できます。

デバイスが認証情報を取得したら、今後の接続のためにそれらをローカルに保存する必要があります。

接続を確立するには、次のパラメータを構成する必要があります。

  • ホスト: <your_cumulocity_url>
  • ユーザー: <tenantID>/<username>(ユーザーエイリアスはサポートされていません)
  • パスワード: <your_cumulocity_password>

詳細については、Hello MQTT セクションを参照してください。

プロセスは次の通りです。

  • Things Cloud は、各デバイスが何らかの形式の固有IDを持っていると仮定しています。たとえば、適切なデバイス識別子はネットワークアダプタの MACアドレス、モバイルデバイスの IMEI、またはハードウェアシリアル番号です。
  • 新しいデバイスを使用する際、この固有IDをデバイス登録に入力し、デバイス管理アプリケーション内でデバイスを起動します。
  • デバイスはこのIDを MQTT ClientId の一部として使用し、製品サポートから問い合わせ可能な静的ユーザー認証情報を使用します。
  • デバイスはトピック s/dcr にサブスクライブします。
  • デバイスはトピック s/ucr に連続した空のメッセージのパブリッシュを開始し、認証情報を取得する準備ができたことをサーバーに通知します。
  • 次に、デバイス登録ページでデバイスからの接続を承認する必要があります。
  • デバイスが次の空のメッセージを送信すると、70,<tenantID>,<username>,<password> の形式の認証情報を受け取ることができます。

認証情報を受信した後、デバイスはMQTT接続を閉じて、受信した認証情報で新しい接続を作成できます。

ステップ 1: デバイスを確認する

クライアントがデータを送信しデバイスが存在しないときに MQTTはデバイスの自動作成をサポートするため、このステップはデバイスを手動で作成する場合にのみ必要です。

デバイスの作成は、静的テンプレート 100 を使用して実行できます。このテンプレートは、デバイスがまだ存在しない場合にのみ作成するため、デバイスのブートのたびに何もせずに使用できます。

デバイスは、クライアントがMQTT ClientIdで使用するIDに自動的にリンクされます。

100,Device Name,Device Type
備考
Things Cloud があらかじめ用意している静的テンプレートに使われているトピックは s/us です。

ステップ 2: 子デバイスを確認する

ルートデバイスと同様に、その子デバイスも自動デバイス作成の対象となります。

このステップを手動で行うには、子デバイスを作成するための 静的テンプレート 101 を送信します。テンプレートは、子デバイスが存在しない場合にのみ作成します。

101,Unique Child ID,Child Name,Child Type

ステップ 3: トピックにサブスクライブする

デバイスがオペレーションをサポートしている場合は、必要なすべてのトピック(静的テンプレートおよびSmartREST 2.0)をサブスクライブする必要があります。

サイクルフェーズ

ステップ A: CSV データを送信する

デバイスはアクティブなMQTT接続を保持している間、静的テンプレートのトピックまたはSmartRESTテンプレートのトピックのいずれかでパブリッシュして、サーバーにデータを送信できます。

MQTT ClientId に基づいて、物理デバイスは Things Cloud 内のデバイスオブジェクトに直接接続されます。したがって、送信するデータは自動的にデバイスに接続されます。

子デバイスにデータを送信するには、デバイス階層 で説明されているトピックにデータをパブリッシュします。

ステップ B: CSV オペレーションを受信する

トピックをサブスクライブすると、デバイスは自動的に Things Cloud にオペレーションを受け取りたいことを伝えます。作成されたオペレーションは、静的テンプレートまたはデバイスが定義するテンプレートを使用して自動的に解析されます。

MQTT の実装

このセクションでは、MQTTプロトコルの実装の詳細を示します。 Things Cloudの実装は、MQTTバージョン3.1.1をサポートしています。

MQTT 標準接続

Things Cloud は TCP と Web ソケットの両方で MQTT をサポートしています。URL として、利用しているテナントのドメイン(例:mytenant.je1.thingscloud.ntt.com/mqtt)、もしくは次の形式のインスタンスのドメイン mqtt.<instance_domain>(例:mqtt.je1.thingscloud.ntt.com)を利用できます(例: mqtt.je1.thingscloud.ntt.com)。

使用可能なポート:

  TCP WebSockets
SSL 8883 443
no SSL 1883 80
備考
クラウドシステムではポート 80 が無効になります。

ポート 8883 は、クライアント認証に証明書を使用する双方向 SSL と、クライアント認証にユーザー名とパスワードを使用する一方向 SSL の 2 種類の SSL をサポートします。 双方向 SSL サポートはデフォルトで有効になっています。無効にするには、製品サポート にお問い合わせください。

備考
WebSocketsを使用するには、パス/mqttに接続し、WebSocket通信のMQTT標準に従う必要があります。

SmartREST ペイロード

Things Cloud の MQTT 実装は、SmartREST をペイロードとして使用します。 SmartRESTは、CSVに似たメッセージプロトコルで、サーバーサイドのテンプレートを使用してThings Cloudでデータを作成します。REST APIの高い表現力を取り入れていますが、組み込みデバイスのJSON解析の複雑さを回避するために、JSONをカンマ区切り値(CSV)に置き換えています。 さらに、CSVのシンプルでコンパクトな構文により、モバイルネットワークを介したIoT通信でも非常に効率的です。 他のHTTP APIと比較して、モバイルトラフィックを最大80%節約できます。

備考
プラットフォームへのすべてのMQTT接続は、最大許容メッセージサイズは16,184バイト(約16キロバイト)です。メッセージヘッダーと本文の両方が含まれます。ヘッダーサイズはさまざまですが、最小サイズは2バイトです。本文のサイズはトピックとペイロードを合わせたサイズです。

SmartREST の基本

SmartRESTメッセージは、各パラメータがカンマで区切られた1行で構成されています。最初のパラメータはメッセージを定義するIDです。メッセージ間に改行を使用することで、1回のパブリッシュで複数のメッセージを送信できます。

SmartRESTエスケープ

CSV(カンマ区切り値)形式は、SmartRESTエンドポイントとの通信に使用されます。正常に通信するためには以下の規則に従う必要があります。

  • すべての行は\nで終了する必要があります
  • 値は常にカンマ(,)で区切られている必要があります
  • 値に二重引用符(")、カンマ(,)、前後の空白、改行(\n)、キャリッジリターン(\r)、タブを含む場合、二重引用符(")で囲む必要があります。二重引用符(")は、バックスラッシュ(\)を前に付けてエスケープする必要があります。

サーバーからクライアントに送信されるメッセージにも同様のエスケープ規則が適用されます。

パブリッシュの例:

100,"This value, needs escaping",This value does not need escaping

サブスクライブの例:

511,myDeviceSerial,"execute this\nand this\nand ""this"""
備考
\nは出力(例: コンソールやUI)中では新規の行を作成しません。新規の行を作成するには、改行文字(ASCII 0A)を使用する必要があります。

デバイス階層

MQTTセッションは1つのデバイスにリンクされますが、このデバイスの下には自由に設定可能なデバイス階層を持つことができます。

すべての子デバイスには、デバイスの作成時に定義された一意のIDが必要です。ルートデバイスの一意のIDと階層内の一意のIDを組み合わせて使用することをお勧めします。

ルートデバイスの代わりに子デバイスのデータを作成するには、子デバイスの一意のIDをトピックの別のセクションとして追加します(例: s/us/myChildDeviceIdentifier)。

クライアントは、それぞれのトピックをサブスクライブすることにより、階層内のすべての子デバイスに対するオペレーションを自動的に受信します。子デバイスごとにサブスクライブする必要はありません。

受信されたすべてのオペレーションには、テンプレートIDの後に、そのオペレーションが作成されたデバイス/子デバイスのIDが含まれます(その後に他のオペレーションパラメータが続きます)。

MQTT機能

MQTT認証

Things Cloudとの通信において、MQTTは以下の2つの方法で認証をサポートしています。

  • ユーザー名とパスワード。MQTTユーザー名は、<tenantID/username>の形式でテナントIDとユーザー名を含める必要があります。
  • デバイス証明書。デバイスには、信頼されたルート証明書につながる証明書のチェーン全体が含まれている必要があります。 また、デバイス証明書のみが提供される場合、直近の発行者証明書をプラットフォームのトラストストアにアップロードする必要があります。さらに、サーバー証明書も自身のトラストストアに含める必要があります。

トラブルシューティング

デバイスから正しいユーザー名とパスワードが送信されるが、同時に不正な証明書も送信される

プラットフォームが双方向 SSL をサポートするように構成されており、デバイスに無効な証明書を含む構成されたキーストアがあり、基本認証を使用したい場合は、接続中に証明書の送信をオフにすることをお勧めします。 証明書の有効期限が切れているか、ルート証明書がプラットフォームにアップロードされていないため、証明書が無効である可能性があります。 デバイスのソフトウェアでの証明書の送信をオフにしてください。 それが不可能な場合、接続を機能させるには次の点を確認してください。

  • プラットフォームのトラストストアを空にすることはできません。 少なくとも 1 つの信頼できる証明書をプラットフォームにアップロードする必要があります。
  • デバイスの MQTT クライアントは、ハンドシェイク中にサーバーから返された承認された発行者リストにルート証明書が見つからない場合、証明書を送信しないように構成する必要があります。 ほとんどの場合、これは自動的に行われます。 MQTT クライアントと Java 11 では動作しないことが知られていますが、Java 8 では動作します。
  • この状況をサポートするには、プラットフォームをそれに応じて構成する必要があります。 製品サポートまでお問い合わせください。
  • 上記のすべてのケースが満たされているにも関わらず、証明書の検証によりデバイス接続が拒否される場合は、おそらく他のテナントが、デバイスから送信された証明書の 1 つと同じ「コモンネーム」を持つ証明書をアップロードした可能性があります。 この場合、デバイスは常に証明書を使用して独自に認証しようとします。

MQTT ClientId

MQTT ClientIdは、接続されている各クライアントを一意に識別するフィールドです。 Things Cloud実装もClientIdを使用して、クライアントを直接デバイスにリンクします。したがって、ClientIdには次の形式を使用する必要があります。

connectionType:deviceIdentifier:defaultTemplateIdentifier

フィールド 必須 説明
connectionType いいえ 接続タイプのデフォルト表示:d(デバイス)
deviceIdentifier はい デバイスの一意の識別子。例:IMEI、シリアル番号
defaultTemplateIdentifier いいえ テンプレート識別子に関する詳細は
MQTT静的テンプレートを確認してください

クライアントの最も単純なバージョンでは、MQTT ClientIdは単にdeviceIdentfierにすることができます。デバイス接続として自動的に解釈されます。

重要
コロン文字はThings Cloudでは特別な意味を持つため、deviceIdentifierでは使用しないでください。

ClientIdの例:

mySerialNumber
d:mySerialNumber
d:mySerialNumber:myDefaultTemplate

MQTT ClientIdの一意性は、deviceIdentifierによってのみ決定されます。したがって、上記の例では、同時に接続できるクライアントは1つだけです。 証明書によるSSL接続では、deviceIdentifierは使用されている証明書(デバイスにより提供される証明書チェーンのうち最初のもの)の「コモンネーム」と一致している必要があります。

MQTTサービス品質(QoS)

Things Cloud実装は、MQTT QoSの3つのレベルすべてをサポートします。

  • QoS 0: 最大1回
    • クライアントは一度だけメッセージを送信します。
    • サーバーからの応答はありません。
  • QoS 1: 1回以上
    • クライアントはサーバーからの確認応答を受け取るまでメッセージを送信し続けます。
  • QoS 2: 1回のみ
    • クライアントはメッセージを送信します。
    • サーバーは確認応答を返します(メッセージは保持されます)。
    • クライアントはリリースコマンドを送信します。
    • サーバーはメッセージを処理し、再度確認応答を返します。

オペレーショントピックまたはエラートピックをサブスクライブする場合は、トピックのサブスクライブ時にクライアントが定義したQoS内のすべてのメッセージを配信します。

MQTTクリーンセッション

Things Cloudは、クリーンセッションを「1」(true)に設定する必要があります。現在のところ、クリーンセッションを無効にしても完全に動作することは保証できませんので、常にクリーンセッションを有効にすることを推奨します。

MQTT保持フラグ

現在のThings Cloud実装では、デバイスがデータをパブリッシュするトピックへのサブスクリプションは許可されていません。このトピックに保持フラグを付けてデータをパブリッシュすることはできますが、フラグを付けずにデータを送信することと実質的な違いはありません。 Things Cloudがパブリッシュするオペレーションやエラーなどのメッセージには、保持フラグは含まれません。

MQTT last will

MQTTでは、「last will」は接続時に指定し、クライアントが接続を失ったときに実行されるメッセージです。例えば、last willメッセージとして 400,c8y_ConnectionEvent,"デバイス接続が失われました。" 、last willトピックとして s/usを指定すると、デバイスが接続を失うたびにイベントが発生します。

備考
「last will」が実行されると、デバイスの可用性が更新されます。

MQTT リターンコード

MQTT エラーが発生した場合、プラットフォームはゼロ以外のリターンコードを含むCONNACKメッセージで応答します。 このメッセージは、問題があることを示す最初の手がかりです。 このようなリターンコードは、401 などの REST API HTTP コードと同様に扱うことができます。 これらは、予期しないエラーや権限の不足などの理由で返される可能性があります。

CONNACKCONNECTメッセージに対する応答であるだけでなく、プラットフォームで発生したエラーを通知する方法でもあります。 したがって、通常の接続中に直接アクションを行わなくても、このメッセージを 2 回目に受信する可能性があります。 ほとんどの MQTT クライアントは、接続を閉じる必要があるかのように0以外のコードでCONNACKを扱うため、これは接続の終了を知らせる方法でもあります。 詳細は以下を参照してください。

以下の表は、Things Cloudによって返されるエラーのリストを示しています。

コード 標準メッセージ トラブルシューティング
0 Connection accepted 問題ありません。接続は機能しています。
1 Connection refused,
unacceptable protocol version
MQTT プロトコルのサポートされていないバージョン。
現在、Things Cloudでは 3.1 と 3.1.1 のみが許可されています。
2 Connection refused, identifier rejected ClientId がプラットフォームに受け入れられません。
3 Connection refused, Server unavailable 一般的なプラットフォーム側のエラー。
内部エラーや不明な認証の問題で受信されることもあります。
ネットワークの問題で受信できます。
このエラーは一時的なものでありデバイスの状態とは
無関係であるため、通常の解決策は後で再試行することです。
4 Connection refused, bad username or password 認証情報が正しくありません (パスワードが空ではありませんが、
ユーザー名やパスワードが間違っています)。
証明書を使用して認証する場合、
このエラーが返されることはありません。
5 Connection refused, not authorized ほとんどがデバイス側に関連した問題で、
デバイスにアクセス許可がない、または禁止されている操作を行っている場合に使用されます。
例えば、クライアントが不正なメッセージを送信したり、
メッセージの公開など、最初に認証を行わずに操作を実行しようとした場合などです。
証明書の認証に関する問題(コモンネームが間違っている、
自動登録が失敗したなど)が発生した場合にスローされます。
また、デバイス データの受信に関する一般的な問題や、
プラットフォーム上のデバイスの状態に関連する
その他の認証の問題でもスローされます。
例えば、デバイスのマネージドオブジェクト問題や、
アクセス権限が突然削除された場合などです。
この状況では、プラットフォーム上で調査と修正の適用を
行う必要がある場合があります。
MQTT バージョン 3.1 を使用している場合、clientId が長すぎると、
このエラーが発生する可能性があります。
これは、clientId が 24 文字以上の場合に発生する可能性があります。
最後に、特に接続中のパフォーマンスの問題など、
予期しない例外が発生した場合にもスローされる可能性があります。
したがって、一時的なパフォーマンスの問題を解決するには、接続を数回繰り返すことが良い方法です。

公式の MQTT 接続リターン コードの詳細については、MQTT Version 3.1.1 > 3.2 CONNACK - Acknowledge connection requestを参照してください。

デバッグ

開発中に開発者をサポートするために、トピックs/eをサブスクライブできます。このトピックでは、デバイスからパブリッシュ中に発生するデバッグメッセージおよびエラーメッセージを取得できます。

備考
このトピックは、純粋にクライアントの開発をサポートするために設計されています。メッセージが冗長であり、データ使用量を大幅に増加させる可能性があるため、常にこのチャネルをサブスクライブすることはお勧めしません。また、このトピックを使用して、そのトピックで受信した内容に基づいてデバイスのアクションをトリガーしないでください。レスポンスチャネルではありません。

MQTTブローカ証明書

MQTT ブローカーは、メイン環境ドメインに割り当てられた証明書を使用します。 MQTT ブローカーは、常にTLS ハンドシェイク中に、これらの証明書をデバイスに送信します。 さらに、エンタープライズテナント(親テナント)はSSL管理機能を経由してMQTTブローカの証明書をカスタマイズすることはできません。

MQTT JWTセッショントークンの取得

x.509 証明書を使用してプラットフォームに接続する、Java で実装された Things Cloud MQTT サンプル クライアントのコードは、ここから入手できます: https://github.com/Cumulocity-IoT//cumulocity-examples/tree/develop/mqtt-client。 このサンプル クライアントでは、Eclipse Paho の実装が使用されています。詳細については、Webサイト (https://www.eclipse.org/paho/index.php?page=documentation.php) で説明されています。

以下は、Eclipse Paho クライアントを使用するために必要な依存関係を Maven に追加する方法を示す例です。

<dependency>
    <groupId>org.eclipse.paho</groupId>
    <artifactId>org.eclipse.paho.client.mqttv3</artifactId>
    <version>${paho.version}</version>
</dependency>

次に、MQTT クライアントのインスタンスを 1 行で作成できます。

MqttClient mqttClient = new MqttClient(BROKER_URL, "d:" + CLIENT_ID, new MemoryPersistence());

BROKER_URL には、ssl://<cumulocity url>:8883のように、クライアントが接続するプロトコル、URL、ポートが含まれている必要があります。 CLIENT_ID 値は、使用されるデバイス証明書のコモンネームの値と一致する必要があります。 証明書のコモンネームには : 文字を含めることはできません。詳細は MQTT ClientId を参照してください。 「d:」プレフィクスは、デバイス接続のためにThings Cloud で使用されているため、削除または変更しないでください。SSL 接続を確立するために設定する必要があるのは、コードフラグメントにパスを入力することだけです。

sslProperties.put(SSLSocketFactoryFactory.KEYSTORE, getClass().getClassLoader().getResource(KEYSTORE_NAME).getPath());
sslProperties.put(SSLSocketFactoryFactory.KEYSTOREPWD, KEYSTORE_PASSWORD);
sslProperties.put(SSLSocketFactoryFactory.KEYSTORETYPE, KEYSTORE_FORMAT);
sslProperties.put(SSLSocketFactoryFactory.TRUSTSTORE, getClass().getClassLoader().getResource(TRUSTSTORE_NAME).getPath());
sslProperties.put(SSLSocketFactoryFactory.TRUSTSTOREPWD, TRUSTSTORE_PASSWORD);
sslProperties.put(SSLSocketFactoryFactory.TRUSTSTORETYPE, TRUSTSTORE_FORMAT);
  • 証明書のコモンネームには : 文字を含めることはできません。詳細は MQTT ClientId を参照してください。
  • KEYSTORE_NAMEは、キーストアへのパスです。キーストアには、デバイス自体を認証するために使用する秘密鍵と証明書のチェーンが含まれています。
  • KEYSTORE_PASSWORD は、キーストアがその秘密鍵を使用するために作成されたパスワードです。
  • KEYSTORE_FORMAT - はファイル形式に応じて「JKS」または「PKCS12」にする必要があります。 パスは KEYSTORE_NAME によって提供されます。
  • TRUSTSTORE_NAME は、サーバーの証明書が含まれるトラストストアへのパスです。
  • TRUSTSTORE_PASSWORD はトラストストアにアクセスするためのパスワードです。
  • TRUSTSTORE_FORMAT は、ファイル形式に応じて「JKS」または「PKCS12」にする必要があります。 パスは TRUSTSTORE によって提供されます。

このデータを入力すると、サンプルクライアントは提供されたデータを使用し、証明書を用いて指定されたプラットフォームに接続します。 この例では、接続用のコールバックを作成する方法も示しています。 まず最初に、インターフェース、MqttCallbackExtended を実装するクラスを作成します。 次に、このようなクラスを作成し、そのインスタンスを MQTT クライアントに提供できます: mqttClient.setCallback(this);

一般的に、MQTT Eclipse Paho クライアントは Java Development Kit の一部である Java Secure Socket Extension を使用して SSL によるセキュアな接続を提供します。 JSSE は、開発者がそのクラスを使用して構成できる SSL および TLS プロトコルの Java 実装を提供します。 Java Secure Socket Extension のドキュメントでは、SSL 接続がどのように確立されるかを示し、実装をカスタマイズする例をいくつか提供しています。 完全なドキュメントは公式Oracleウェブサイトで入手できます。

MQTTのサンプル

Hello MQTT

このチュートリアルでは、事前定義されたメッセージ(「静的テンプレート」)を使用して、Things Cloud で MQTT を使用する方法を学びます。

前提条件

このチュートリアルを進めるには、次の前提条件を確認してください。

  • Things Cloud にアクセスするための有効なテナント、ユーザ、パスワードがあること。
  • MQTTBox または同様の MQTT ツールをインストールしていること。
備考
  • このチュートリアルのスクリーンショットでは MQTTBox を使用しています。ほかのツールでは表示が異なる場合があります。
  • トライアルテナントを使用している場合、デフォルトユーザはこのチュートリアルでは使用できません。代わりに追加のユーザを作成してください。テナント ID と URL データも、トライアルテナント情報とは異なります。

MQTT 接続の設定

MQTT 接続を設定するには、次の接続パラメータを渡す必要があります(以下のスクリーンショットを参照)。

  • MQTT Client Name – クライアントを識別するための名前を付けます。たとえば、Things Cloud MQTT です。
  • MQTT Client Id – 「Generate a random ID」ボタンを使用するか(ほとんどのツールにはこのようなボタンがあります)、自分で指定します。この ID は Things Cloud 内のデバイスにリンクされます。同じデバイスに再接続するには、同じ ID を使用します。
  • Protocol – 使用するプロトコルを選択します。たとえば、mqtt/tcp です。
  • Host – URL にテナントドメインを指定します。たとえば、mytenant.je1.thingscloud.ntt.com/mqtt です。
  • Username – この場合、ユーザ名は <tenantID>/<service-user> の形式です。Things Cloud プラットフォームへのログインに使用するものと同じ認証情報を使用できます(ユーザエイリアスはサポートされていません)。以下の例のように、テナント ID が「t76543210」、サービスユーザが「manga」の場合、ユーザ名は「t76543210/manga」です。
  • Password: サービスユーザのパスワード。

Things Cloud は TCP と WebSockets の両方で MQTT をサポートしています。URL としては、テナントドメイン(たとえば mytenant.je1.thingscloud.ntt.com/mqtt)または mqtt.<instance_domain> 形式のインスタンスドメイン(たとえば mqtt.je1.thingscloud.ntt.com)を使用できます。

Example MQTTBox Configuration

備考
テナント ID とテナントドメインの違いをよりよく理解するには、Things Cloud OpenAPI仕様 の Tenants > Tenant ID and tenant domain を参照してください。

「clean session」などのほかの設定は、この例では重要ではありません。必要に応じて変更できます。Save をクリックすると、次のスクリーンショットのような画面が表示されます。

MQTTBox Established Connection

上部バーに Not Connected と表示された青いボタンがある場合は、設定(特にユーザ名とパスワード)を確認してください。ボタンが緑色であれば、Things Cloud への MQTT 接続は正常に確立されています。

データの送信

このチュートリアルのすべての MQTT パブリッシュメッセージは、トピック s/us に送信されます。これは、Things Cloud の事前提供された静的テンプレートに使用されるトピックです。

MQTTBox Publish Message

デバイスの作成

最初に送信するメッセージでデバイスを作成します。静的テンプレートは自動デバイス作成をサポートしていますが、この例ではデバイスを手動で作成します。テンプレート 100 は新しいデバイスを作成します。これは 2 つのオプションパラメータ(deviceName、deviceType)とともに使用できます。

100,My first MQTT device,c8y_MQTTdevice

その後、このデバイスはデバイス管理アプリケーション内で新しいデバイスとして見つかります。デバイスの Identity タブに切り替えると、デバイスを MQTT ClientId にリンクするための ID が自動的に作成されていることがわかります。

名前とタイプ以外には、このデバイスにはそれ以上の情報がないため、マスターデータを追加する必要があります。

1 回のパブリッシュで、改行区切りにより複数の静的テンプレートを使用できます(1 行につき 1 テンプレート)。この機能は、1 つのパブリッシュメッセージでハードウェア情報とデバイスに必要な間隔を設定するために使用されます。

ハードウェアはテンプレート 110 で設定できます。これは 3 つのパラメータ(serialNumber、model、revision)を取ります。静的テンプレートのオプションパラメータは、設定したくない場合は空のままにできます。ハードウェアについては、すべてのパラメータがオプションです。

必要な間隔はテンプレート 117 で設定でき、1 つのパラメータ(分単位の間隔)だけを取ります。

110,,MQTT test model,1.2.3
117,10

デバイス管理アプリケーションでデバイスの Info ページを再読み込みすると、追加した情報が表示されるはずです。

メジャーメントの作成

これでデバイスにはいくつかのマスターデータが設定され、メジャーメントの送信を開始できます。 静的テンプレートを使用して直接作成できるメジャーメントがいくつかあります。

  • 210: 信号強度メジャーメント
  • 211: 温度メジャーメント
  • 212: バッテリーメジャーメント

温度メジャーメントとバッテリーメジャーメントは、値と時刻をパラメータとして取るだけです。信号強度については、2 つの値(RSSI と BER)を渡すことができます。

Things Cloud の MQTT 実装でタイムスタンプを渡すことは常にオプションです。渡さない場合、サーバは現在のサーバ時刻でタイムスタンプを自動的に作成します。

この例ではこの機能を使用します。また、最後のパラメータを設定しない場合は、残りのカンマを入力する必要もありません。

210,-87
211,24
212,95

上記のメジャーメントに加えて、テンプレート 200 を使用して、よりカスタムなメジャーメントを作成することもできます。これは、メジャーメントフラグメント、series、値、単位、時刻をパラメータとして取ります。

200,myCustomTemperatureMeasurement,fahrenheit,75.2,F

デバイス管理アプリケーションで再読み込みすると、デバイスの Measurements タブに、新しく追加されたメジャーメントを含む 4 つのグラフが表示されるはずです。

アラームの作成

次に、このデバイス用にいくつかのアラームを作成します。4 つのアラーム重大度に対応するアラーム作成用テンプレートがあります。

  • 301: CRITICAL
  • 302: MAJOR
  • 303: MINOR
  • 304: WARNING

それぞれ、type(必須)、text、time(後者 2 つはオプション)を指定します。

301,gpio_critical,There is a GPIO alarm
304,simple_warning

これでデバイスのアラームリストには、critical アラーム 1 件と warning アラーム 1 件が含まれるはずです。

warning には text を設定していないため、デフォルトのアラームテキストで作成されたことに注意してください。

次に、critical アラームを再度クリアします。これを行うには、クリアするアラームの type を参照するテンプレート 306 を使用します。

306,gpio_critical

その後、critical アラームはクリアされるはずです。

MQTT 実装ではアラーム ID を扱う必要がなかったことに注意してください。Things Cloud がこの部分を引き受けるため、デバイス通信をできるだけ簡単にできます。

イベントの作成

次に、デバイス用にいくつかの位置イベントを作成します。必要に応じて、都市の緯度と経度を取得するために LatLong website を使用できます。

テンプレート 401 を使用すると位置イベントを作成でき、緯度、経度、高度、精度、時刻をパラメータとして取りますが、ここでは最初の 2 つだけを使用します。

401,51.227741,6.773456

デバイス管理アプリケーションではイベントリストに 1 つのイベントが表示されますが、位置は更新されていません。これは REST ではこれらが別々のリクエストだからです。MQTT では、テンプレート 401 の代わりにテンプレート 402 を使用できます。これは 401 とまったく同じように動作しますが、さらにデバイス自体の位置も更新します。

402,51.227741,6.773456

これでデバイスに Location タブと Tracking タブの両方が表示され、Location タブには最後の位置イベントと同じ緯度と経度が表示されるはずです。

データの受信

ここまでは、MQTT を使用してクライアントからサーバへデータを送信するだけでした。次は、サーバからクライアントへデータを送信します。

これを実現するには、まず対象のトピックをサブスクライブする必要があります。ここでは 2 つのサブスクリプションを行います。

  • s/ds : デバイス用の静的オペレーションテンプレートをサブスクライブします
  • s/e : デバッグに使用できるエラートピックをサブスクライブします

Subscribe フィールドに両方のトピックを順に入力し、Subscribe をクリックできます。QoS の選択はこの例では重要ではありません。

その後、MQTTBox は次のようになります。

MQTTBox Subscribed Topics

オペレーションの受信

現在の状態では、UI にオペレーション用のタブは表示されません。ここまでは、デバイスが正確に何をサポートしているかは不明でしたが、サポートされるオペレーションのリストはテンプレート 114 で変更できます。ここにサポートされるオペレーションのリストを追加できます。

ここでは、configuration と shell のサポートを追加します。

114,c8y_Command,c8y_Configuration

UI を再読み込みすると、2 つの新しいタブ(ConfigurationShell)が表示されます。

これで UI から shell コマンドを作成し、Execute をクリックできます。

MQTTBox では、s/ds サブスクリプションに対して新しいメッセージを受信しているはずです。

MQTTBox Received Operation

511 は受信したオペレーションの種類(この場合は c8y_Command)を示しています。続いて、専用オペレーションを持つデバイスを特定するための deviceIdentifier が続きます。これは、複数の子を持つ階層がある場合に必要です。その場合、どの子に対するオペレーションなのかを知る必要があります。最後に、オペレーション固有のパラメータがあります。c8y_Command の場合はコマンドテキストのみです。

オペレーションを受信した後、クライアントによるオペレーション処理を開始できます。アラームのステータス変更と同様に、テンプレートにオペレーションの type を追加できます。

501,c8y_Command

処理が完了したら、テンプレート 503 を使用してオペレーションを successful に設定できます。

オペレーション type に加えて、このオペレーションはオペレーションの種類に応じた追加パラメータも取ることができます。c8y_Command に対して結果を返すことができます。

503,c8y_Command,Everything went fine
エラーから学ぶ

トピック s/e は、何か問題が発生した場合のデバッグに役立ちます。 たとえば、次を送信しようとすると

999,I made this up

テンプレート 999 が不明であるため、このトピックにメッセージが表示されます。

40,999,No static template for this message id

Hello MQTT C

このチュートリアルでは、事前定義されたメッセージ(「静的テンプレート」)を使用して、Things Cloud で C の MQTT クライアントを使用する方法を学びます。

前提条件

このチュートリアルを進めるには、次の前提条件を確認してください。

  • Things Cloud にアクセスするための有効なテナント、ユーザ、パスワードがあること。
  • gcc コンパイラがインストールされていることを確認します。
$ gcc --version
gcc (Ubuntu 5.4.0-6ubuntu1~16.04.4) 5.4.0 20160609
Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  • MQTT C Paho Client をダウンロード、コンパイル、インストールします。Paho の詳細については、Paho website を参照してください。

「Hello, MQTT world!」クライアントの開発

Things Cloud 用の非常にシンプルな「Hello, world!」MQTT クライアントを開発するには、次のことを行う必要があります。

  • アプリケーションを作成する
  • アプリケーションをビルドして実行する
アプリケーションの作成

ソースファイル(たとえば hello_mqtt.c)を作成し、次の内容を記述します。

#include "stdlib.h"
#include "string.h"
#include "unistd.h"
#include "MQTTClient.h"

#define ADDRESS     "<<serverUrl>>"
#define CLIENTID    "<<clientId>>"

void publish(MQTTClient client, char* topic, char* payload) {
    MQTTClient_message pubmsg = MQTTClient_message_initializer;
    pubmsg.payload = payload;
    pubmsg.payloadlen = strlen(pubmsg.payload);
    pubmsg.qos = 2;
    pubmsg.retained = 0;
    MQTTClient_deliveryToken token;
    MQTTClient_publishMessage(client, topic, &pubmsg, &token);
    MQTTClient_waitForCompletion(client, token, 1000L);
    printf("Message '%s' with delivery token %d delivered\n", payload, token);
}

int on_message(void *context, char *topicName, int topicLen, MQTTClient_message *message) {
    char* payload = message->payload;
    printf("Received operation %s\n", payload);
    MQTTClient_freeMessage(&message);
    MQTTClient_free(topicName);
    return 1;
}

int main(int argc, char* argv[]) {
    MQTTClient client;
    MQTTClient_create(&client, ADDRESS, CLIENTID, MQTTCLIENT_PERSISTENCE_NONE, NULL);
    MQTTClient_connectOptions conn_opts = MQTTClient_connectOptions_initializer;
    conn_opts.username = "<<tenant_ID>>/<<username>>";
    conn_opts.password = "<<password>>";

    MQTTClient_setCallbacks(client, NULL, NULL, on_message, NULL);

    int rc;
    if ((rc = MQTTClient_connect(client, &conn_opts)) != MQTTCLIENT_SUCCESS) {
        printf("Failed to connect, return code %d\n", rc);
        exit(-1);
    }
    //create device
    publish(client, "s/us", "100,C MQTT,c8y_MQTTDevice");
    //set hardware information
    publish(client, "s/us", "110,S123456789,MQTT test model,Rev0.1");
    //listen for operation
    MQTTClient_subscribe(client, "s/ds", 0);

    for (;;) {
        //send temperature measurement
        publish(client, "s/us", "211,25");
        sleep(3);
    }
    MQTTClient_disconnect(client, 1000);
    MQTTClient_destroy(&client);
    return rc;
}

<<clientId>><<serverUrl>><<tenant_ID>><<username>><<password>> を自分のデータに置き換えてください。

Things Cloud MQTT プロトコルは、セキュリティ保護されていない TCP 接続と、セキュリティ保護された SSL 接続の両方をサポートしています(たとえば tcp://mqtt.je1.thingscloud.ntt.com:1883 または ssl://mqtt.je1.thingscloud.ntt.com:8883)。そのため、<<serverUrl>> には自分に合ったものを選択できます。 SSL を使用する場合は、MQTTClient_SSLOptions を設定し、それを MQTTClient_connectOptions に設定することを忘れないでください。

main のコードは何を行いますか?

  • MQTT 接続を設定します。
  • 受信メッセージを出力する on_message コールバック関数を登録します。
  • MQTT プロトコル経由で Things Cloud に接続します。
  • C MQTT という名前と c8y_MQTTDevice というタイプで新しいデバイスを作成します。
  • "S123456789" のシリアル、"MQTT test model" のモデル、"Rev0.1" のリビジョンを設定して、デバイスのハードウェア情報を更新します。
  • デバイス用の静的オペレーションテンプレートをサブスクライブします。これにより、新しいオペレーションが作成されるたびに on_message メソッドが呼び出されます。
  • 3 秒ごとに温度メジャーメントを送信します。

publish のコードは何を行いますか?

  • 新しい MQTT メッセージを作成し、ペイロードを設定します。
  • MQTT プロトコル経由でメッセージをパブリッシュします。
  • サーバからのメッセージ配信 ACK を最大 1 秒待機します。

サブスクリプションはデバイス作成後に確立されることに注意してください。そうしないと、指定された clientId に対するデバイスが存在しない場合、サーバはそれを受け付けません。

アプリケーションのビルドと実行

アプリケーションをビルドするには、次のように入力します。

$ gcc hello_mqtt.c -o hello_mqtt -lpaho-mqtt3c

アプリケーションを実行するには、次のように入力します。

$ ./hello_mqtt
Message '100,C MQTT,c8y_MQTTDevice' with delivery token 1 delivered
...

アプリケーションを起動すると、デバイス管理アプリケーションの All devices に、新しいデバイスが表示されるはずです。

さらに、このデバイスに対して新しいオペレーション(たとえば c8y_Restart)が作成されると、その情報がコンソールに出力されます。

エージェントの改善

最初の一歩を踏み出したので、Hello MQTT セクションを参照して、Things Cloud MQTT についてさらに学び、アプリケーションを改善してください。

Hello MQTT Java

このチュートリアルでは、事前定義されたメッセージ(「静的テンプレート」)を使用して、Things Cloud で Java MQTT クライアントを使用する方法を学びます。

前提条件

このチュートリアルを進めるには、次の前提条件を確認してください。

  • Things Cloud にアクセスするための有効なテナント、ユーザ、パスワードがあること。
  • Maven 3 と少なくとも Java 7 がインストールされていることを確認します。
$ mvn -v
Maven home: /Library/Maven/apache-maven-3.6.0
Java version: 1.8.0_201, vendor: Oracle Corporation, runtime: /Library/Java/JavaVirtualMachines/jdk1.8.0_201.jdk/Contents/Home/jre
Default locale: en_GB, platform encoding: UTF-8
OS name: "mac os x", version: "10.14.2", arch: "x86_64", family: "mac"

Maven は Maven website からダウンロードできます。

「Hello, MQTT world!」クライアントの開発

Things Cloud 用の非常にシンプルな「Hello, world!」MQTT クライアントを開発するには、次のことを行う必要があります。

  • Maven プロジェクトを作成する
  • MQTT Java クライアントライブラリへの依存関係を pom.xml に追加する(この例では Paho Java Client を使用します)
  • Java アプリケーションを作成する
  • Java アプリケーションをビルドして実行する
Maven プロジェクトの作成

Maven でプレーンな Java プロジェクトを作成するには、次のコマンドを実行します。

$ mvn archetype:generate -DgroupId=c8y.example -DartifactId=hello-mqtt-java -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false

これにより、現在のディレクトリに hello-mqtt-java フォルダが作成され、プロジェクトのスケルトン構造が生成されます。

MQTT Java クライアントライブラリの追加

hello-mqtt-java フォルダ内の pom.xml を編集します。MQTT Paho Java Client への依存関係を追加します。

<dependency>
    <groupId>org.eclipse.paho</groupId>
    <artifactId>org.eclipse.paho.client.mqttv3</artifactId>
    <version>[1.2.1,)</version>
</dependency>

Java 9 以降を使用している場合は、Apache Maven Compiler Plugin のページで説明されているように source と target を設定し、次のコードを追加する必要があります。

<properties>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
</properties>
Java アプリケーションの作成

hello-mqtt-java/src/main/java/c8y/example フォルダにある App.java ファイルを編集し、次の内容を記述します。

package c8y.example;

import org.eclipse.paho.client.mqttv3.*;
import java.util.concurrent.*;

public class App {

    public static void main(String[] args) throws Exception {

        // client, user and device details
        final String serverUrl   = "tcp://mqtt.cumulocity.com";     /* ssl://mqtt.je1.thingscloud.ntt.com:8883 for a secure connection */
        final String clientId    = "my_mqtt_java_client";
        final String device_name = "My Java MQTT device";
        final String tenant      = "<<tenant_ID>>";
        final String username    = "<<username>>";
        final String password    = "<<password>>";

        // MQTT connection options
        final MqttConnectOptions options = new MqttConnectOptions();
        options.setUserName(tenant + "/" + username);
        options.setPassword(password.toCharArray());

        // connect the client to Things Cloud
        final MqttClient client = new MqttClient(serverUrl, clientId, null);
        client.connect(options);

        // register a new device
        client.publish("s/us", ("100," + device_name + ",c8y_MQTTDevice").getBytes(), 2, false);

        // set device's hardware information
        client.publish("s/us", "110,S123456789,MQTT test model,Rev0.1".getBytes(), 2, false);

        // add restart operation
        client.publish("s/us", "114,c8y_Restart".getBytes(), 2, false);

        System.out.println("The device \"" + device_name + "\" has been registered successfully!");

        // listen for operations
        client.subscribe("s/ds", new IMqttMessageListener() {
            public void messageArrived (final String topic, final MqttMessage message) throws Exception {
                final String payload = new String(message.getPayload());

                System.out.println("Received operation " + payload);
                if (payload.startsWith("510")) {
                    // execute the operation in another thread to allow the MQTT client to
                    // finish processing this message and acknowledge receipt to the server
                    Executors.newSingleThreadScheduledExecutor().execute(new Runnable() {
                        public void run() {
                            try {
                                System.out.println("Simulating device restart...");
                                client.publish("s/us", "501,c8y_Restart".getBytes(), 2, false);
                                System.out.println("...restarting...");
                                Thread.sleep(TimeUnit.SECONDS.toMillis(5));
                                client.publish("s/us", "503,c8y_Restart".getBytes(), 2, false);
                                System.out.println("...done...");
                            } catch (MqttException e) {
                                e.printStackTrace();
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                    });
                }
            }
        });

        // generate a random temperature (10º-20º) measurement and send it every 7 seconds
        Executors.newSingleThreadScheduledExecutor().scheduleWithFixedDelay(new Runnable() {
            public void run () {
                try {
                    int temp = (int) (Math.random() * 10 + 10);

                    System.out.println("Sending temperature measurement (" + temp + "º) ...");
                    client.publish("s/us", new MqttMessage(("211," + temp).getBytes()));
                } catch (MqttException e) {
                    e.printStackTrace();
                }
            }
        }, 1, 7, TimeUnit.SECONDS);
    }
}

必要に応じて serverUrlclientIddevice_name を置き換えてください。tenant_IDusernamepassword の値を設定して、ユーザ認証情報を指定することを忘れないでください。

Things Cloud MQTT プロトコルは、セキュリティ保護されていない TCP 接続と、セキュリティ保護された SSL 接続の両方をサポートしています(つまり、tcp://mqtt.je1.thingscloud.ntt.com:1883 または ssl://mqtt.je1.thingscloud.ntt.com:8883)。そのため、自分に合ったものを選択して serverUrl に使用できます。

main のコードは何を行いますか?

  • MQTT 接続を設定します。
  • MQTT プロトコル経由で Things Cloud に接続します。
  • 名前 (device_name) とタイプ (c8y_MQTTDevice) を持つ新しいデバイスを作成します。
  • "S123456789" のシリアル、"MQTT test model" のモデル、"Rev0.1" のリビジョンを設定して、デバイスのハードウェア情報を更新します。
  • デバイス用の静的オペレーションテンプレートをサブスクライブし、受信したすべてのオペレーションをコンソールに出力します。c8y_Restart オペレーションの場合は、デバイスの再起動をシミュレートします。
  • 7 秒ごとに温度メジャーメントを送信する新しいスレッドを作成します。

サブスクリプションはデバイス作成後に確立されることに注意してください。そうしないと、指定された clientId に対するデバイスが存在しない場合、サーバはそれを受け付けません。

アプリケーションのビルドと実行

アプリケーションをビルドするには、次のコマンドを使用します。

$ cd hello-mqtt-java
$ mvn clean install
...
[INFO]
[INFO] --- maven-jar-plugin:2.4:jar (default-jar) @ hello-mqtt-java ---
[INFO] Building jar: /home/schm/Pulpit/hello-mqtt-java/target/hello-mqtt-java-1.0-SNAPSHOT.jar
[INFO]
[INFO] --- maven-install-plugin:2.4:install (default-install) @ hello-mqtt-java ---
[INFO] Installing /home/schm/Pulpit/hello-mqtt-java/target/hello-mqtt-java-1.0-SNAPSHOT.jar to /home/schm/.m2/repository/c8y/example/hello-mqtt-java/1.0-SNAPSHOT/hello-mqtt-java-1.0-SNAPSHOT.jar
[INFO] Installing /home/schm/Pulpit/hello-mqtt-java/pom.xml to /home/schm/.m2/repository/c8y/example/hello-mqtt-java/1.0-SNAPSHOT/hello-mqtt-java-1.0-SNAPSHOT.pom
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 2.642 s
[INFO] Finished at: 2017-03-14T09:16:25+01:00
[INFO] Final Memory: 14M/301M
[INFO] ------------------------------------------------------------------------

実行するには、次のコマンドを使用します。

$ mvn exec:java -Dexec.mainClass="c8y.example.App"
...
[INFO]                                                                         
[INFO] ------------------------------------------------------------------------
[INFO] Building hello-mqtt-java 1.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- exec-maven-plugin:1.6.0:java (default-cli) @ hello-mqtt-java ---
Received operation 510,123456789

アプリケーションを起動すると、デバイス管理アプリケーションの All devices に、新しく登録されたデバイスが表示されるはずです。Measurements タブでは、クライアントから送信される温度メジャーメントを確認できます。

さらに、このデバイスに対して新しいオペレーション(たとえば c8y_Restart)が作成されると、その情報がコンソールに出力されます。

エージェントの改善

最初の一歩を踏み出したので、Hello MQTT セクションを参照して、Things Cloud MQTT についてさらに学び、アプリケーションを改善してください。

Hello MQTT Java with certificates

このチュートリアルでは、X.509 証明書を認証に使用して、Things Cloud で Java MQTT クライアントを使用する方法を学びます。

GitHub リポジトリ cumulocity-examples には、X.509 証明書を使用するサンプル Java MQTT クライアントと、このチュートリアルで使用する必要なすべてのスクリプトがあります。

前提条件

このチュートリアルを進めるには、次の前提条件を確認してください。

  • Hello MQTT Java チュートリアルに基づいて Java クライアントが正しく設定されていること。
  • Things Cloud にアクセスするための有効なテナント、ユーザ、パスワードがあること。
  • 有効な証明書があること。ない場合は、次のセクションの手順に従って生成してください。
有効な証明書を生成するには

有効な証明書がない場合は、デバイス証明書 の手順に従って、テスト目的で生成できます。

  1. cumulocity-examples リポジトリからスクリプトをダウンロードします。
  2. ルート自己署名証明書を作成し(00createRootSelfSignedCertificate.sh スクリプトを実行)、それをテナントにアップロードします。これは UI のデバイス管理アプリケーション または REST で行えます。
  3. 証明書を作成して署名します(01createSignedCertificate.sh スクリプトを実行)。
  4. 証明書をキーストアに移動します(02moveCertificatesToKeystore.sh スクリプトを実行)。さらに、キーストア内でデバイスのリーフ証明書のみが必要な場合は、–leafonly オプションを使用します。
  5. 最後に、次のコマンドを実行して信頼された証明書をキーストアにインポートします。
$ keytool -importcert -file c8y-mqtt-server.cer -keystore chain-with-private-key-iot-device-0001.jks -alias "Alias"

証明書付き「Hello, MQTT world!」クライアントの開発

証明書付きで Things Cloud 用の「Hello, world!」MQTT クライアントを開発するには、次のことを行う必要があります。

  • 証明書をコピーしてプラットフォームにアップロードする
  • MQTT クライアントの設定を変更する
証明書をコピーしてアップロードするには

ファイル chain-iot-device-0001.pem から証明書をコピーし、POST リクエストを使用してプラットフォームにアップロードします。

エンドポイント: /tenant/tenants/{tenantId}/trusted-certificates
認証: Basic
Content-Type: application/json
リクエスト本文:

{
    "status" :  "ENABLED",
    "name" : "sampleName",
    "autoRegistrationEnabled" : "true",
    "certInPemFormat" : "<<certificate in pem format>>"
}
設定を変更するには

MQTT クライアントの設定を変更するには、ファイル chain-with-private-key-iot-device-0001.jks をリソースフォルダにコピーし、設定を行います。使用するスクリプト(手順 4)ではパスワード changeit を使用することに注意してください。スクリプト内で値を変更した場合は、次の例の KEYSTORE_PASSWORDTRUSTSTORE_PASSWORD でも同様に変更してください。

// Configuration
private static final String KEYSTORE_NAME = "chain-with-private-key-iot-device-0001.jks";
private static final String KEYSTORE_PASSWORD = "changeit";
private static final String KEYSTORE_FORMAT = "jks";

private static final String TRUSTSTORE_NAME = "chain-with-private-key-iot-device-0001.jks";
private static final String TRUSTSTORE_PASSWORD = "changeit";
private static final String TRUSTSTORE_FORMAT = "jks";

private static final String CLIENT_ID = "iotdevice0001";
private static final String BROKER_URL = "<SSL URL of the platform>";

private MqttClient connect() throws MqttException {
    MqttClient mqttClient = new MqttClient(BROKER_URL, "d:" + CLIENT_ID, new MemoryPersistence());
    MqttConnectOptions options = new MqttConnectOptions();

    options.setCleanSession(true);

    Properties sslProperties = new Properties();
    sslProperties.put(SSLSocketFactoryFactory.KEYSTORE, getClass().getClassLoader().getResource(KEYSTORE_NAME).getPath());
    sslProperties.put(SSLSocketFactoryFactory.KEYSTOREPWD, KEYSTORE_PASSWORD);
    sslProperties.put(SSLSocketFactoryFactory.KEYSTORETYPE, KEYSTORE_FORMAT);
    sslProperties.put(SSLSocketFactoryFactory.TRUSTSTORE, getClass().getClassLoader().getResource(TRUSTSTORE_NAME).getPath());
    sslProperties.put(SSLSocketFactoryFactory.TRUSTSTOREPWD, TRUSTSTORE_PASSWORD);
    sslProperties.put(SSLSocketFactoryFactory.TRUSTSTORETYPE, TRUSTSTORE_FORMAT);
    sslProperties.put(SSLSocketFactoryFactory.CLIENTAUTH, true);

    options.setSSLProperties(sslProperties);
    mqttClient.setCallback(this);
    System.out.println("Connecting to the broker at " + BROKER_URL);
    mqttClient.connect(options);

    return mqttClient;
}

デバイスは、標準デバイスとしてパブリッシュおよびサブスクライブできるようになりました。最初の接続前には、たとえばユーザの作成など、ほかの操作は不要であることに注意してください。ユーザは 自動登録 プロセス中に作成されます。

備考
証明書を使用して接続する MQTT クライアントでは、パスワード、ユーザ、テナントを設定する必要はありません。Things Cloud は、提供された証明書によってテナントとユーザを認識します。

Hello MQTT browser-based

このチュートリアルでは、事前定義されたメッセージ(「静的テンプレート」)を使用して、Things Cloud でブラウザベースの MQTT クライアントを使用する方法を学びます。

前提条件

このチュートリアルを進めるには、次の前提条件を確認してください。

  • Things Cloud にアクセスするための有効なテナント、ユーザ、パスワードがあること。

「Hello, MQTT world!」クライアントの開発

Things Cloud 用の非常にシンプルな「Hello, world!」MQTT クライアントを開発するには、次のことを行う必要があります。

  • HTML ファイルを作成し、MQTT JavaScript クライアントを含める(この例では Paho JavaScript Client を使用します)
  • JavaScript アプリケーションを作成する
  • アプリケーションを実行する
JavaScript アプリケーションの作成

HTML ファイル(たとえば hello_mqtt_js.html)を作成し、次の内容を記述します。

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>Hello MQTT World</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <script src="https://cdnjs.cloudflare.com/ajax/libs/paho-mqtt/1.0.1/mqttws31.min.js"></script>
    <script src="main.js" defer></script>
</head>
<body>
    <div id="logger"></div>
</body>
</html>

JavaScript ファイル main.js を作成し、次の内容を記述します。

// client, user and device details
var serverUrl   = "ws://mqtt.cumulocity.com/mqtt";     /* wss://mqtt.je1.thingscloud.ntt.com/mqtt for a secure connection */
var clientId    = "my_mqtt_js_client";
var device_name = "My JS MQTT device";
var tenant      = "<<tenant_ID>>";
var username    = "<<username>>";
var password    = "<<password>>";

var undeliveredMessages = [];
var temperature = 25;

// configure the client to Things Cloud
var client = new Paho.MQTT.Client(serverUrl, clientId);

// display all incoming messages
client.onMessageArrived = function (message) {
    log('Received operation "' + message.payloadString + '"');
    if (message.payloadString.indexOf("510") == 0) {
        log("Simulating device restart...");
        publish("s/us", "501,c8y_Restart");
        log("...restarting...");
        setTimeout(function() {
            publish("s/us", "503,c8y_Restart");
            log("...done...");
        }, 1000);
    }
};

// display all delivered messages
client.onMessageDelivered = function onMessageDelivered (message) {
    log('Message "' + message.payloadString + '" delivered');
    var undeliveredMessage = undeliveredMessages.pop();
    if (undeliveredMessage.onMessageDeliveredCallback) {
        undeliveredMessage.onMessageDeliveredCallback();
    }
};

function createDevice () {
    // register a new device
    publish("s/us", "100," + device_name + ",c8y_MQTTDevice", function() {
        // set hardware information
        publish("s/us", "110,S123456789,MQTT test model,Rev0.1", function() {
            publish('s/us', '114,c8y_Restart', function() {
                log('Enable restart operation support');
                //listen for operation
                client.subscribe("s/ds");
            })

            // send temperature measurement
            setInterval(function() {
                publish("s/us", '211,'+temperature);
                temperature += 0.5 - Math.random();
            }, 3000);
        });
    });
}

// send a message
function publish (topic, message, onMessageDeliveredCallback) {
    message = new Paho.MQTT.Message(message);
    message.destinationName = topic;
    message.qos = 2;
    undeliveredMessages.push({
        message: message,
        onMessageDeliveredCallback: onMessageDeliveredCallback
    });
    client.send(message);
}

// connect the client to Things Cloud
function init () {
    client.connect({
        userName: tenant + "/" + username,
        password: password,
        onSuccess: createDevice
    });
}

// display all messages on the page
function log (message) {
    document.getElementById('logger').insertAdjacentHTML('beforeend', '<div>' + message + '</div>');
}

init();

必要に応じて serverUrlclientIddevice_name を置き換えてください。tenant_IDusernamepassword の値を設定して、ユーザ認証情報を指定することを忘れないでください。

Things Cloud MQTT プロトコルは、セキュリティ保護されていない TCP 接続と、セキュリティ保護された SSL 接続の両方をサポートしています(つまり、ws://mqtt.je1.thingscloud.ntt.com/mqtt または wss://mqtt.je1.thingscloud.ntt.com/mqtt)。そのため、自分に合ったものを選択して serverUrl に使用できます。

このコードは何を行いますか?

  • MQTT 接続を設定します。
  • 受信したすべてのメッセージを表示する onMessageArrived コールバック関数を登録します。c8y_Restart オペレーションの場合は、デバイスの再起動をシミュレートします。
  • パブリッシュメッセージの配信後に呼び出される onMessageDelivered コールバック関数を登録します。
  • ページが完全に読み込まれた後、関数 init が呼び出され、MQTT プロトコル経由で Things Cloud に接続します。
  • 接続が確立されたら、createDevice 関数を呼び出します。
  • 名前 (device_name) とタイプ (c8y_MQTTDevice) を持つ新しいデバイスを作成します。
  • "S123456789" のシリアル、"MQTT test model" のモデル、"Rev0.1" のリビジョンを設定して、デバイスのハードウェア情報を更新します。
  • デバイス用の静的オペレーションテンプレートをサブスクライブします。これにより、新しいオペレーションが作成されるたびに onMessageArrived メソッドが呼び出されます。
  • 3 秒ごとに温度メジャーメントを送信します。

サブスクリプションはデバイス作成後に確立されることに注意してください。そうしないと、指定された clientId に対するデバイスが存在しない場合、サーバはそれを受け付けません。

アプリケーションの実行

ブラウザで hello_mqtt_js.html ファイルを開きます。デバイス管理アプリケーションの All devices に、新しく登録されたデバイスが表示されるはずです。Measurements タブでは、クライアントから送信される温度メジャーメントを確認できます。

さらに、このデバイスに対して新しいオペレーション(たとえば c8y_Restart)が作成されると、関連情報がブラウザページに表示されます。

エージェントの改善

最初の一歩を踏み出したので、Hello MQTT セクションを参照して、Things Cloud MQTT についてさらに学び、アプリケーションを改善してください。

Hello MQTT Node.js

このチュートリアルでは、事前定義されたメッセージ(「静的テンプレート」)を使用して、Things Cloud で Node.js MQTT クライアントを使用する方法を学びます。

前提条件

このチュートリアルを進めるには、次の前提条件を確認してください。

  • Node.js とパッケージマネージャ(npm)がインストールされていること。
  • Things Cloud にアクセスするための有効なテナント、ユーザ、パスワードがあること。

「Hello, MQTT world!」クライアントの開発

Things Cloud 用の非常にシンプルな「Hello, world!」MQTT クライアントを開発するには、次のことを行う必要があります。

  • Node.js アプリケーションを作成する
  • MQTT ミドルウェアをインストールする(この例では MQTT.js ライブラリを使用します)
  • アプリケーションを実行する
Node.js アプリケーションの作成

依存関係やアプリケーションに関する基本情報を一覧化するために、package.json ファイルを作成します。

{
  "dependencies": {
    "mqtt": "*"
  },
  "scripts": {
    "start": "node app.js"
  }
}

package.json ファイルで指定した起動スクリプト(app.js)を作成し、次の内容を記述します。

// MQTT dependency https://github.com/mqttjs/MQTT.js
const mqtt = require("mqtt");

// client, user and device details
const serverUrl   = "tcp://mqtt.cumulocity.com";
const clientId    = "my_mqtt_nodejs_client";
const device_name = "My Node.js MQTT device";
const tenant      = "<<tenant_ID>>";
const username    = "<<username>>";
const password    = "<<password>>";

var temperature   = 25;

// connect the client to Things Cloud
const client = mqtt.connect(serverUrl, {
    username: tenant + "/" + username,
    password: password,
    clientId: clientId
});

// once connected...
client.on("connect", function () {
    // ...register a new device with restart operation
    client.publish("s/us", "100," + device_name + ",c8y_MQTTDevice", function() {
        client.publish("s/us", "114,c8y_Restart", function() {
            console.log("Device registered with restart operation support");
        });

        // listen for operations
        client.subscribe("s/ds");

        // send a temperature measurement every 3 seconds
        setInterval(function() {
            console.log("Sending temperature measurement: " + temperature + "º");
            client.publish("s/us", "211," + temperature);
            temperature += 0.5 - Math.random();
        }, 3000);
    });

    console.log("\nUpdating hardware information...");
    client.publish("s/us", "110,S123456789,MQTT test model,Rev0.1");
});

// display all incoming messages
client.on("message", function (topic, message) {
    console.log('Received operation "' + message + '"');
    if (message.toString().indexOf("510") == 0) {
        console.log("Simulating device restart...");
        client.publish("s/us", "501,c8y_Restart");
        console.log("...restarting...");
        setTimeout(function() {
            client.publish("s/us", "503,c8y_Restart");
            console.log("...done...");
        }, 1000);
    }
});

必要に応じて serverUrlclientIddevice_name を置き換えてください。tenant_IDusernamepassword の値を設定して、ユーザ認証情報を指定することを忘れないでください。

Things Cloud MQTT プロトコルは、セキュリティ保護されていない TCP 接続と、セキュリティ保護された SSL 接続の両方をサポートしています。どちらの接続タイプを選択しても、serverUrl は同じままにする必要があります(mqtt.je1.thingscloud.ntt.com のように)。

このコードは何を行いますか?

  • MQTT 接続を設定します。
  • 接続が確立されると、名前 (device_name) とタイプ (c8y_MQTTDevice) を持つ新しいデバイスを登録します。
  • デバイスに再起動機能を追加します。
  • オペレーションを受信するためにサブスクライブします。
  • 3 秒ごとにランダムな温度メジャーメントを送信します。
  • "S123456789" のシリアル、"MQTT test model" のモデル、"Rev0.1" のリビジョンを設定して、デバイスのハードウェア情報を更新します。
  • 受信したすべてのメッセージを監視します。c8y_Restart オペレーションの場合は、デバイスの再起動をシミュレートします。

サブスクリプションはデバイス作成後に確立されることに注意してください。そうしないと、指定された clientId に対するデバイスが存在しない場合、サーバはそれを受け付けません。

アプリケーションの実行

アプリケーションを実行する前に、MQTT ミドルウェアをインストールする必要があります。これを行うには、次のコマンドを実行します。

$ npm install

インストールは 1 回だけ行えば十分です。その後は、次のコマンドを実行するだけです。

$ npm start

デバイス管理アプリケーションの All devices に、新しく登録されたデバイスが表示されるはずです。Measurements タブでは、クライアントから送信される温度メジャーメントを確認できます。

さらに、このデバイスに対して新しいオペレーション(たとえば c8y_Restart)が作成されると、その関連情報がコンソールに出力されます。

エージェントの改善

最初の一歩を踏み出したので、Hello MQTT セクションを参照して、Things Cloud MQTT についてさらに学び、アプリケーションを改善してください。

Hello MQTT Python

このチュートリアルでは、事前定義されたメッセージ(「静的テンプレート」)を使用して、Things Cloud で Python MQTT クライアントを使用する方法を学びます。

前提条件

このチュートリアルを進めるには、次の前提条件を確認してください。

  • Things Cloud にアクセスするための有効なテナント、ユーザ、パスワードがあること。
  • Python 3 がインストールされていることを確認します。
$ python3 --version
Python 3.8.5

Python は www.python.org からダウンロードできます。

  • システムのパッケージマネージャまたは pip を使用して Python Paho クライアントをインストールします。
$ pip install paho-mqtt
備考
上記コマンドはシステムに Paho をインストールします。この例のためだけにインストールするには、virtualenv の使用を検討してください。
備考
macOS では、pip コマンドが見つからない場合に sudo easy_install pip を実行する必要があることがあります。

「Hello, MQTT world!」クライアントの開発

Things Cloud 用の非常にシンプルな「Hello, world!」MQTT クライアントを開発するには、次のことを行う必要があります。

  • Python スクリプトを作成する
  • スクリプトを実行する
Python スクリプトの作成

スクリプトファイル(たとえば hello_mqtt.py)を作成し、次の内容を記述します。

# /usr/bin/env python3
# -*- coding: utf-8 -*-

import paho.mqtt.client as mqtt
import time, random, threading
import multiprocessing as mp

# client, user and device details
serverUrl   = "mqtt.cumulocity.com"
clientId    = "my_mqtt_python_client"
device_name = "My Python MQTT device"
tenant      = "<<tenant_ID>>"
username    = "<<username>>"
password    = "<<password>>"

# task queue to overcome issue with paho when using multiple threads:
#   https://github.com/eclipse/paho.mqtt.python/issues/354
task_queue = mp.Queue()

# display all incoming messages
def on_message(client, userdata, message):
    payload = message.payload.decode("utf-8")
    print(" < received message " + payload)
    if payload.startswith("510"):
        task_queue.put(perform_restart)

# simulate restart
def perform_restart():
    print("Simulating device restart...")
    publish("s/us", "501,c8y_Restart", wait_for_ack = True);

    print("...restarting...")
    time.sleep(1)

    publish("s/us", "503,c8y_Restart", wait_for_ack = True);
    print("...restart completed")

# send temperature measurement
def send_measurement():
    print("Sending temperature measurement...")
    temperature = random.randint(10, 20)
    publish("s/us", "211,{}".format(temperature))

# publish a message
def publish(topic, message, wait_for_ack = False):
    QoS = 2 if wait_for_ack else 0
    message_info = client.publish(topic, message, QoS)
    if wait_for_ack:
        print(" > awaiting ACK for {}".format(message_info.mid))
        message_info.wait_for_publish()
        print(" < received ACK for {}".format(message_info.mid))

# display all outgoing messages
def on_publish(client, userdata, mid):
    print(" > published message: {}".format(mid))

# main device loop
def device_loop():
    while True:
        task_queue.put(send_measurement)
        time.sleep(7)

# connect the client to Things Cloud and register a device
client = mqtt.Client(clientId)
client.username_pw_set(tenant + "/" + username, password)
client.on_message = on_message
client.on_publish = on_publish

client.connect(serverUrl)
client.loop_start()
publish("s/us", "100," + device_name + ",c8y_MQTTDevice", wait_for_ack = True)
publish("s/us", "110,S123456789,MQTT test model,Rev0.1")
publish("s/us", "114,c8y_Restart")
print("Device registered successfully!")

client.subscribe("s/ds")

device_loop_thread = threading.Thread(target = device_loop)
device_loop_thread.daemon = True
device_loop_thread.start()

# process all tasks on queue
try:
    while True:
        task = task_queue.get()
        task()
except (KeyboardInterrupt, SystemExit):
    print("Received keyboard interrupt, quitting ...")
    exit(0)

必要に応じて serverUrlclientIddevice_name を置き換えてください。tenant_IDusernamepassword の値を設定して、ユーザ認証情報を指定することを忘れないでください。

Things Cloud MQTT プロトコルは、セキュリティ保護されていない TCP 接続と、セキュリティ保護された SSL 接続の両方をサポートしています。そのため、ポートを設定する際は正しいものを使用することを忘れないでください。どちらの接続タイプを選択しても、serverUrl は同じままにする必要があります(mqtt.je1.thingscloud.ntt.com のように)。

上記の例では TCP 接続を使用しています。SSL 接続を使用する場合は、Paho MQTT クライアントの適切な設定を使用することを忘れないでください。詳細は www.eclipse.org を参照してください。

このスクリプトは何を行いますか?

  • MQTT 接続を設定します。
  • 受信メッセージを出力する on_message コールバック関数を登録します。c8y_Restart オペレーションの場合は、デバイスの再起動をシミュレートします。
  • パブリッシュメッセージの配信後に呼び出される on_publish コールバック関数を登録します。
  • MQTT プロトコルを介して Things Cloud に接続します。
  • 名前 (device_name) とタイプ (c8y_MQTTDevice) を持つ新しいデバイスを作成します。
  • "S123456789" のシリアル、"MQTT test model" のモデル、"Rev0.1" のリビジョンを設定して、デバイスのハードウェア情報を更新します。
  • デバイス用の静的オペレーションテンプレートをサブスクライブします。これにより、新しいオペレーションが作成されるたびに on_message メソッドが呼び出されます。
  • 7 秒ごとに温度メジャーメントを送信する device_loop_thread を開始します。
  • すべてのタスクを 1 つずつ実行する task_queue を準備します。

publish メッセージは何を行いますか?

  • 指定されたトピックについて、指定されたメッセージを MQTT 経由でパブリッシュします。
  • メッセージをパブリッシュするときに QoS 2 を使用します。そのため、メッセージが配信されたことを確実にするために、サーバ ACK を待機します(対応するメッセージ ID で on_publish メソッドが呼び出されるまで)。

サブスクリプションはデバイス作成後に確立されることに注意してください。そうしないと、指定された clientId に対するデバイスが存在しない場合、サーバはそれを受け付けません。

スクリプトの実行

スクリプトを実行するには、次のコマンドを使用します。

$ python3 hello_mqtt.py

アプリケーションを起動すると、デバイス管理アプリケーションの All devices に、新しく登録されたデバイスが表示されるはずです。Measurements タブでは、クライアントから送信される温度メジャーメントを確認できます。

さらに、このデバイスに対して新しいオペレーション(たとえば c8y_Restart)が作成されると、その情報がコンソールに出力されます。

エージェントの改善

最初の一歩を踏み出したので、Hello MQTT セクションを参照して、Things Cloud MQTT についてさらに学び、アプリケーションを改善してください。