このトピックでは、IoT Platform Link SDK を Message Queuing Telemetry Transport(MQTT)ベースのモジュールに統合し、関連する構成を完了する方法について説明します。このトピックでは、サンプルコードは Link SDK v3.0.1 に基づいて記述されています。
シナリオ
IoT Platform の Link SDK は、デバイスを IoT Platform に接続し、デバイスを検証し、データ通信を有効にするために使用されます。Link SDK を通信モジュールに統合すると、次の利点が得られます。
- デバイスメーカーは、デバイスのマイクロコントローラユニット(MCU)が IoT Platform への接続を確立する方法に焦点を当てることなく、デバイス上でモジュールの AT コマンドを実行してデバイスを IoT Platform に接続できます。MCU のワークロードは変更されません。
- Alibaba Cloud Partner Network ページには、認定モジュールモデル、購入リンク、開発ガイドが表示されます。デバイスメーカーまたはサービスプロバイダーの場合は、認定通信モジュールを使用してデバイスを IoT Platform に接続できます。
次の図は、Link SDK が統合された通信モジュールを含むデバイスを IoT Platform に接続するプロセスを示しています。

次のセクションでは、デバイスメーカーとしてデバイスを構成するプロセスについて説明します。
- Link SDK が統合された通信モジュールを購入します。
- MCU で AT コマンドを実行してデバイスを IoT Platform に接続し、IoT Platform にデータを送信または IoT Platform からデータを受信します。
- IoT Platform にクラウドサービスをデプロイしてデバイスを管理します。
モジュールプロバイダーは、モジュールで次の手順を実行する必要があります。
- 想定どおりに Link SDK をモジュールに統合します。
- MCU がデバイスを IoT Platform に接続するために実行できる AT コマンドを提供します。
使用上の注意
次のセクションでは、Link SDK を MQTT ベースのモジュールに統合する方法について説明します。これは、モジュールプロバイダーが Link SDK の統合プロセスを理解するのに役立ちます。複雑さを軽減するために、次のセクションでは、Link SDK のデバイス署名モジュールをデバイスのモジュールに統合する方法について説明します。このようにして、モジュールを使用してデバイスを IoT Platform に接続できます。
モジュールプロバイダーの場合は、Thing Specification Language(TSL)モデル関連の機能、無線(OTA)関連の機能、デバイスシャドウ関連の機能など、Link SDK のより多くの機能を統合することをお勧めします。このようにして、デバイスメーカーは、デバイスが IoT Platform に接続されているときに、より多くの機能を使用できます。
MQTT ベースのモジュールを使用する場合は、モジュールに統合されている Link SDK の API 操作を呼び出して、モジュールの MQTT 機能モジュールに基づいて IoT Platform MQTT ブローカーに接続するために必要なクライアント ID、ユーザー名、およびパスワードを生成できます。その後、モジュールプロバイダーは、そのデータを使用して IoT Platform MQTT ブローカーへの接続を確立し、MQTT トピックをサブスクライブし、トピックにデータを送信できます。
IoT Platform で Basic Edition プロダクトを作成する
モジュールプロバイダーがサンプルコードをデバッグする場合、モジュールプロバイダーはテストプロダクトとテストデバイスを作成して、Link SDK が想定どおりに動作するかどうかを確認する必要があります。デバイスを作成するには、次の手順を実行します。
- IoT Platform コンソール にログインします。モジュールプロバイダーとしてコンソールにログインする場合は、Alibaba Cloud アカウントを作成する必要があります。Alibaba Cloud アカウントは無料で作成できます。
- テストデバイスを作成します。デバイスの詳細ページで、デバイスの DeviceName と DeviceSecret を取得できます。
次のセクションでは、Link SDK を統合するプロセスについて説明します。
Link SDK を統合するプロセス
モジュールプロバイダーが Link SDK をモジュールに統合する場合、プロセスには次の図に示すように複数のステージが含まれます。

Link SDK を構成してコードを抽出する
Link SDK は多数の機能を提供します。過剰な RAM メモリとフラッシュメモリが Link SDK によって消費されるのを防ぐために、Link SDK によって提供されるツールを使用して、必要な機能モジュールのみを構成および抽出できます。
Link SDK を構成する
次のセクションでは、モジュールプロバイダーとして必要な機能を構成する方法について説明します。
構成コマンドを実行する
- Linux
Link SDK のルートディレクトリに移動し、次のコマンドを実行します。
make menuconfig
- Windows
Link SDK のルートディレクトリに移動し、config.bat ファイルを実行します。
config.bat
上記のいずれかの方法を使用して、Link SDK の構成ツールを起動します。次の図は、ツールの GUI を示しています。

- オプションの前にアスタリスク(*)が表示されている場合、関連する機能は有効になっています。そうでない場合、機能は無効になっています。
- ツールには、構成できる機能が表示されます。オプションが選択されていない場合、Link SDK で構成できない機能は引き続き有効です。
- GUI で、スペースキーを押してオプションを選択またはクリアし、キーパッドの上矢印キーまたは下矢印キーを押して異なるオプションを切り替えます。
- オプションに関する情報を取得するには、矢印キーを押してカーソルをオプションに移動し、H キーを押します。この場合、オプションの目的と、オプションを有効または無効にした後に実行されるシステム操作を示す情報が表示されます。
ビジネスシナリオに基づいて、次のオプションを選択できます。
- 開発環境が stdint.h をサポートしている場合は、PLATFORM_HAS_STDINT を選択します。
- 開発環境が malloc/free をサポートしている場合は、PLATFORM_HAS_DYNMEM を選択します。
- お使いの環境でオペレーティングシステムが実行されている場合は、PLATFORM_HAS_OS を選択します。
他のオプションは選択しないでください。構成が完了したら、カーソルを Exit に移動して Enter キーを押してツールを終了し、プロンプトが表示されたら構成を保存します。
Link SDK のコードを抽出する
次のセクションでは、Link SDK のコードを抽出する方法について説明します。
抽出コマンドを実行する
- Linux
Link SDK のルートディレクトリに移動し、次のコマンドを実行します。
sh ./extract.sh
- Windows
Link SDK のルートディレクトリに移動し、extract.bat ファイルを実行します。
extract.bat

Link SDK のファイルをプロジェクトにインポートする
出力ディレクトリにある eng ディレクトリをプロジェクトディレクトリにコピーし、コードファイルをプロジェクトにインポートできます。
コードファイルは、eng/dev_sign、eng/infra、eng/wrappers ディレクトリに格納されています。プロジェクトをコンパイルするときは、ヘッダーファイルで上記のパスを指定する必要があります。
ハードウェアアブストラクションレイヤー(HAL)関数を実装する
なし。
Link SDK を既存の MQTT 機能モジュールと統合する
MQTT クライアント ID、ユーザー名、およびパスワードを生成する。
MQTT クライアントを MQTT ブローカーに接続するときは、クライアント ID、ユーザー名、およびパスワードを指定する必要があります。Link SDK の IOT_Sign_MQTT()関数を呼び出して、情報を生成できます。
int32_t IOT_Sign_MQTT(iotx_mqtt_region_types_t region, iotx_dev_meta_info_t *meta, iotx_sign_mqtt_t *signout)
この関数を使用する場合は、サンプルコードで dev_sign_internal.h ヘッダーファイルを指定する必要があります。
#include "dev_sign_internal.h"
入力パラメーター
- region
接続先の IoT Platform エンドポイント。パラメーターの有効値は、eng/infra/infra_defs.h ファイルで定義されています。
typedef enum {
IOTX_CLOUD_REGION_SHANGHAI, /* Shanghai */
IOTX_CLOUD_REGION_SINGAPORE, /* Singapore */
IOTX_CLOUD_REGION_JAPAN, /* Japan */
IOTX_CLOUD_REGION_USA_WEST, /* America */
IOTX_CLOUD_REGION_GERMANY, /* Germany */
IOTX_CLOUD_REGION_CUSTOM, /* Custom setting */
IOTX_CLOUD_DOMAIN_MAX /* Maximum number of domain */
} iotx_mqtt_region_types_t;
モジュールが中国本土で購入できる場合は、パラメーターを IOTX_CLOUD_REGION_SHANGHAI に設定します。
meta
デバイスに関する ID 情報。次のコードは、パラメーターのデータ構造を示しています。
typedef struct {
char product_key[IOTX_PRODUCT_KEY_LEN + 1];
char product_secret[IOTX_PRODUCT_SECRET_LEN + 1];
char device_name[IOTX_DEVICE_NAME_LEN + 1];
char device_secret[IOTX_DEVICE_SECRET_LEN + 1];
} iotx_dev_meta_info_t;
[IoT Platform コンソール] でプロダクトが作成されると、デバイスごとにデバイスメーカーによって上記の変数の値が要求されます。実際のプロダクト開発シナリオでは、MCU は AT コマンドを実行して変数の値をモジュールに送信します。
出力パラメーター
- signout
このパラメーターには、クライアントを MQTT ブローカーに接続するときに必要なクライアント ID、ユーザー名、およびパスワードが含まれています。次のコードは、パラメーターのデータ構造を示しています。
typedef struct {
char hostname[DEV_SIGN_HOSTNAME_MAXLEN];
uint16_t port;
char clientid[DEV_SIGN_CLIENT_ID_MAXLEN];
char username[DEV_SIGN_USERNAME_MAXLEN];
char password[DEV_SIGN_PASSWORD_MAXLEN];
} iotx_sign_mqtt_t;
hostname 変数は、Alibaba Cloud MQTT ブローカーのエンドポイントを指定します。port 変数は、Alibaba Cloud MQTT ブローカーのポート番号を指定します。
戻り値
呼び出しが成功した場合、関数は 0 を返します。呼び出しが失敗した場合、関数は -1 を返します。
例
eng\examples\dev_sign_example.c ファイルの次のコードは、IOT_Sign_MQTT()関数を呼び出す方法を示しています。
#define EXAMPLE_PRODUCT_KEY "a1X2bEnP82z"
#define EXAMPLE_PRODUCT_SECRET "7jluWm1zql7bt8qK"
#define EXAMPLE_DEVICE_NAME "example1"
#define EXAMPLE_DEVICE_SECRET "ga7XA6KdlEeiPXQPpRbAjOZXwG8ydgSe"
/* 例で何かを印刷する場合は、この HAL を実装するか、独自のシステムの「printf」を使用します */
void HAL_Printf(const char *fmt, ...);
int main(int argc, char *argv[])
{
iotx_mqtt_region_types_t region = IOTX_CLOUD_REGION_SHANGHAI;
iotx_dev_meta_info_t meta;
iotx_sign_mqtt_t sign_mqtt;
memset(&meta,0,sizeof(iotx_dev_meta_info_t));
memcpy(meta.product_key,EXAMPLE_PRODUCT_KEY,strlen(EXAMPLE_PRODUCT_KEY));
memcpy(meta.product_secret,EXAMPLE_PRODUCT_SECRET,strlen(EXAMPLE_PRODUCT_SECRET));
memcpy(meta.device_name,EXAMPLE_DEVICE_NAME,strlen(EXAMPLE_DEVICE_NAME));
memcpy(meta.device_secret,EXAMPLE_DEVICE_SECRET,strlen(EXAMPLE_DEVICE_SECRET));
if (IOT_Sign_MQTT(region,&meta,&sign_mqtt) < 0) {
return -1;
}
...
}
この例では、product_key、product_secret、device_name、device_secret パラメーターに特定の値が指定されています。実際のシナリオでは、値は MCU によってモジュールに送信される必要があります。
モジュールプロバイダーが Link SDK をデバッグする場合、モジュールプロバイダーは [IoT Platform コンソール] でテストプロダクトとテストデバイスを作成し、product_key、product_secret、device_name、device_secret パラメーターの値を取得する必要があります。値は、デバイスに対して IoT Platform によって生成されます。
モジュールプロバイダー ID とモジュールモデルをアップロードする
モジュールプロバイダーが IoT Platform でモジュールを検証する場合、モジュールプロバイダーはモジュールプロバイダー ID とモジュールのモデルを送信する必要があります。このようにして、IoT Platform は、モジュールプロバイダー ID またはモジュールモデルによって IoT Platform に接続されているデバイスの数を取得できます。
Link SDK を統合する前に、Alibaba Cloud に連絡して、件名「モジュールまたはチップモデルアプリケーション」のメールを linkcertification@list.alibaba-inc.com に送信して、モジュールプロバイダー ID とモジュールモデルを取得してください。モジュールプロバイダーでない場合は、モジュールプロバイダー ID を申請する必要はありません。
モジュールが IoT Platform に接続されたら、次のコードを環境にコピーし、コード内の関数を実行して情報を送信します。pid パラメーターはモジュールプロバイダーの ID を指定し、mid パラメーターはモジュールモデルの ID を指定します。
#define PID_STRING_LEN_MAX 32 /* pid パラメーターの値の最大長。値は文字列です。 */
#define MID_STRING_LEN_MAX 32 /* mid パラメーターの値の最大長。値は文字列です。 */
int example_report_pid_mid(void *pclient, const char *product_key, const char *device_name, const char *pid, const char *mid)
{
int res = 0;
iotx_mqtt_topic_info_t topic_msg;
const char topic_frag1[] = "/sys/";
const char topic_frag2[] = "/thing/deviceinfo/update";
char topic[sizeof(topic_frag1) + sizeof(topic_frag2) + IOTX_PRODUCT_KEY_LEN + IOTX_DEVICE_NAME_LEN] = {0};
const char payload_frag1[] = "{\"id\":\"0\",\"version\":\"1.0\",\"params\":[{\"attrKey\":\"SYS_MODULE_ID\",\"attrValue\":\"";
const char payload_frag2[] = "\",\"domain\":\"SYSTEM\"},{\"attrKey\":\"SYS_PARTNER_ID\",\"attrValue\":\"";
const char payload_frag3[] = "\",\"domain\":\"SYSTEM\"}],\"method\": \"thing.deviceinfo.update\"}";
char payload[sizeof(payload_frag1) + sizeof(payload_frag2) + sizeof(payload_frag3) + PID_STRING_LEN_MAX + MID_STRING_LEN_MAX] = {0};
if (strlen(pid) > PID_STRING_LEN_MAX || strlen(mid) > MID_STRING_LEN_MAX) {
return -1;
}
/* 文字列を組み合わせて MQTT トピックを作成します。 */
memcpy(topic, topic_frag1, strlen(topic_frag1));
memcpy(topic + strlen(topic), product_key, strlen(product_key));
memcpy(topic + strlen(topic), "/", 1);
memcpy(topic + strlen(topic), device_name, strlen(device_name));
memcpy(topic + strlen(topic), topic_frag2, strlen(topic_frag2));
/* 文字列を組み合わせて MQTT トピックのペイロードを作成します。ペイロードには、pid パラメーターと mid パラメーターの値が含まれています */
memcpy(payload, payload_frag1, strlen(payload_frag1));
memcpy(payload + strlen(payload), mid, strlen(mid));
memcpy(payload + strlen(payload), payload_frag2, strlen(payload_frag2));
memcpy(payload + strlen(payload), pid, strlen(pid));
memcpy(payload + strlen(payload), payload_frag3, strlen(payload_frag3));
topic_msg.qos = IOTX_MQTT_QOS0;
topic_msg.retain = 0;
topic_msg.dup = 0;
topic_msg.payload = (void *)payload;
topic_msg.payload_len = strlen(payload);
/* MQTT IOT_MQTT_Publish 関数を呼び出して、pid パラメーターと mid パラメーターの値を含むメッセージを送信します。
ビジネスシナリオに基づいて MQTT IOT_MQTT_Publish 関数を変更します。 */
res = IOT_MQTT_Publish(pclient, topic, &topic_msg);
if (res < 0) {
return -1;
}
return 0;
}
デバッグ
モジュールを IoT Platform に接続する
モジュールプロバイダーは、モジュールを IoT Platform に接続するために使用できるコードを記述する必要があります。モジュールの MQTT 機能モジュールは、MQTT ブローカーに接続するために使用される関数を備えています。Link SDK の IOT_Sign_MQTT()関数をすべて呼び出した後に返されるエンドポイント、ポート番号、クライアント ID、ユーザー名、およびパスワードを関数に指定します。
次のサンプルコードは、Link SDK と mosquitto という名前のオープンソース MQTT ライブラリを統合しています。
// IOT_Sign_MQTT()関数を呼び出して、ユーザー名、パスワード、およびクライアント ID を取得します。
IOT_Sign_MQTT(region,&meta,&sign_mqtt);
mosquitto_lib_init();
// クライアント ID を指定し、cleansession パラメーターを構成します。
mosq = mosquitto_new(sign_mqtt.clientid,0/*セッションをクリーンアップしない*/,NULL);
if(mosq==NULL){
printf("エラー: mosquitto クライアントの作成に失敗しました\n\r");
return(-1);
}
// MQTT ブローカーに接続するために必要なユーザー名とパスワードを指定します。
if(0 != mosquitto_username_pw_set(mosq, sign_mqtt.username, sign_mqtt.password)){
printf("エラー: ユーザー名またはパスワードの設定に失敗しました\n\r");
return(-1);
}
...
// エンドポイントとポート番号を指定して、MQTT ブローカーへの接続を確立します。
if(mosquitto_connect(mosq, sign_mqtt.hostname, sign_mqtt.port, kaInterval)){
printf("エラー: クラウドへの接続に失敗しました。\n\r");
sleep(1);
return -1;
}
MQTT 接続を確立するときは、キープアライブ間隔を指定する必要があります。60 秒の間隔を指定することをお勧めします。モジュールプロバイダーは、MCU が間隔を指定するために呼び出すことができる AT コマンドを実装できます。IoT Platform は、30 ~ 1,200 秒のキープアライブ間隔をサポートしています。
モジュールが IoT Platform に接続された後、モジュールと IoT Platform 間の MQTT 接続が閉じられない場合、モジュールはオンライン状態のままになります。IoT Platform でテストデバイスを見つけて、デバイスのステータスを表示できます。次の図は、オンライン状態のデバイスを示しています。

デバイスが想定どおりに IoT Platform にデータを送信できるかどうかを確認する
モジュールが IoT Platform に接続された後、デバイスは /${productKey}/${deviceName}/get トピックにメッセージを送信して、データが想定どおりに IoT Platform に送信できるかどうかを確認できます。
デフォルトでは、デバイスは /${productKey}/${deviceName}/get トピックに対するサブスクライブ権限を持っています。メッセージが IoT Platform に送信された後にメッセージがドロップされるのを防ぐために、トピックの権限をサブスクライブとパブリッシュに変更することをお勧めします。このようにして、サンプルプログラムは障害なく想定どおりに実行できます。
サンプルコード:
int res = 0;
iotx_mqtt_topic_info_t topic_msg;
const char *fmt = "/%s/%s/get";
char *topic = NULL;
int topic_len = 0;
char *payload = "hello,world";
topic_len = strlen(fmt) + strlen(product_key) + strlen(device_name) + 1;
topic = HAL_Malloc(topic_len);
if (topic == NULL) {
HAL_Printf("メモリが不足しています\n");
return -1;
}
memset(topic, 0, topic_len);
// トピックを生成します。
HAL_Snprintf(topic, topic_len, fmt, product_key, device_name);
// メッセージを生成します。
memset(&topic_msg, 0x0, sizeof(iotx_mqtt_topic_info_t));
topic_msg.qos = IOTX_MQTT_QOS0;
topic_msg.retain = 0;
topic_msg.dup = 0;
topic_msg.payload = (void *)payload;
topic_msg.payload_len = strlen(payload);
// トピックにメッセージを送信します。次の関数を、モジュールに固有の MQTT パブリッシュ関数に置き換えます。
res = IOT_MQTT_Publish(handle, topic, &topic_msg);
[IoT Platform コンソール] で、デバイスの [デバイスログ] タブにデータが受信されているかどうかを確認します。

- タブには、デバイスからメッセージが受信された時刻と、メッセージが受信されたトピックの名前が表示されます。コンテンツは表示されません。
- IoT Platform は、サービス品質(QoS)2 メッセージをサポートしていません。
デバイスがトピックをサブスクライブしているかどうかを確認する
モジュールプロバイダーは、デバイスの /{productKey}/${deviceName}/get トピックのデータをサブスクライブできます。デバイスが IoT Platform にデータを送信した後、IoT Platform はデバイスにデータを送信します。このようにして、モジュールプロバイダーは、デバイスがトピックをサブスクライブしているかどうかを確認できます。サンプルコード:
int res = 0;
const char *fmt = "/%s/%s/get";
char *topic = NULL;
int topic_len = 0;
topic_len = strlen(fmt) + strlen(product_key) + strlen(device_name) + 1;
topic = HAL_Malloc(topic_len);
if (topic == NULL) {
HAL_Printf("メモリが不足しています\n");
return -1;
}
// トピックを構築します
memset(topic, 0, topic_len);
snprintf(topic, topic_len, fmt, product_key, device_name);
/* トピックをサブスクライブし、メッセージを処理する関数を指定します。
次の関数を、モジュールに固有の MQTT サブスクライブ関数に置き換えます。 */
res = IOT_MQTT_Subscribe(handle, topic, IOTX_MQTT_QOS0, example_message_arrive, NULL);
[IoT Platform コンソール] で、モジュールプロバイダーは、データがデバイスに送信されているかどうかを確認できます。

- [デバイスログ] タブには、IoT Platform がデバイスにメッセージを送信した時刻が表示されます。タブには、メッセージの内容は表示されません。
- モジュールプロバイダーは、受信データがモジュールで送信されたデータと同じであるかどうかを確認する必要があります。これにより、データが想定どおりに受信されることが保証されます。
AT コマンドを実装する
モジュールプロバイダーは、MCU が呼び出すことができる AT コマンドを提供する必要があります。MQTT ベースのモジュールを使用する場合は、MQTT 接続の構成、接続の確立、接続の終了、メッセージのサブスクライブ、メッセージのパブリッシュのために呼び出すことができる API 操作を提供する必要があります。モジュールプロバイダーが Link SDK を統合した後、モジュールプロバイダーは Alibaba Cloud に固有のより多くの AT コマンドを実装したり、既存の AT コマンドを変更したりできます。
次の表に、推奨される AT コマンドを示します。
| コマンド | 説明 |
| デバイスの ID 情報を指定する | デバイスの ProductKey、ProductSecret、DeviceName、DeviceSecret を指定します。 |
| IoT Platform エンドポイントを指定する | IoT Platform は、中国本土、米国、日本など、複数のリージョンで利用できます。MCU を接続する IoT Platform エンドポイントに関する情報を指定できます。 |
モジュールプロバイダーの他の既存の AT コマンドを引き続き使用できます。