このトピックでは、Link SDK を TCP ベースのワイドエリアネットワーク(WAN)モジュールに統合する方法について説明します。
IoT Platform の Link SDK は、デバイスを IoT Platform に接続し、デバイスを検証し、データ通信を有効にするために使用されます。通信モジュールに Link SDK を統合すると、次の利点が得られます。
- デバイスメーカーは、デバイスのマイクロコントローラユニット(MCU)が IoT Platform への接続を確立する方法に焦点を当てることなく、デバイス上でモジュールの AT コマンドのみを実行して、デバイスを IoT Platform に接続できます。 MCU のワークロードは変わりません。
- Alibaba Cloud Partner Network ページには、認定モジュールモデル、購入リンク、開発ガイドが表示されます。デバイスメーカーまたはサービスプロバイダーの場合は、認定通信モジュールを使用してデバイスを 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 のより多くの機能を統合する場合、デバイスメーカーはより少ない機能を開発します。モジュールプロバイダーは、無線(OTA)関連機能や Thing Specification Language(TSL)モデル関連機能など、Link SDK のできるだけ多くの機能を統合することをお勧めします。
IoT Platform コンソールでの操作
モジュールに統合された Link SDK が想定どおりに動作するかどうかを確認するには、テストデバイスを IoT Platform に接続する必要があります。 IoT Platform コンソールでプロダクトを作成し、そのプロダクトにデバイスを作成して、デバイスに関する ID 情報を取得する必要があります。
- IoT Platform コンソール にログインします。モジュールプロバイダーとしてコンソールにログインする場合は、Alibaba Cloud アカウントを作成する必要があります。 Alibaba Cloud アカウントは無料で作成できます。
- IoT Platform にログインした後、「プロダクトの作成」トピックに記載されている手順に従ってプロダクトを作成します。プロダクトの詳細ページで、プロダクトの ProductKey と ProductSecret を取得できます。
- テストデバイスを作成します。デバイスの詳細ページで、デバイスの DeviceName と DeviceSecret を取得できます。
Link SDK を統合するプロセス
モジュールプロバイダーが Link SDK をモジュールに統合する場合、プロセスには次の図に示すように複数のステージが含まれます。

Link SDK を構成し、コードを抽出する
Link SDK を構成する
Link SDK は、多数の機能を提供します。次のセクションでは、この例で必要な機能を構成する方法について説明します。
構成コマンドを実行する
- Linux
Link SDK のルートディレクトリに移動し、次のコマンドを実行します。
make menuconfig - Windows
Link SDK のルートディレクトリに移動し、次のコマンドを実行します。
config.bat
上記のいずれかの方法を使用して、Link SDK の構成ツールを起動します。次の図は、ツールの GUI を示しています。

必要な機能を有効にする
GUI で、スペースキーを押して機能を選択またはクリアし、キーパッドの上矢印キーまたは下矢印キーを押して異なるオプションを切り替えます。オプションに関する情報を取得するには、矢印キーを押してカーソルをオプションに移動し、H キーを押します。この場合、オプションの目的と、オプションを選択またはクリアした後に実行されるシステムアクションを示す情報が表示されます。
- コンパイル環境に stdint.h ヘッダーファイルが含まれている場合は、次のオプションを選択します。
PLATFORM_HAS_STDINT
- 組み込みオペレーティングシステムが環境で実行されている場合は、次のオプションを選択します。
PLATFORM_HAS_OS
- モジュールが Message Queuing Telemetry Transport(MQTT)ではなく TCP をサポートしている場合は、次のオプションを有効にする必要があります。
- FEATURE_MQTT_COMM_ENABLED:Alibaba SDK の MQTT API を提供して、デバイスと IoT Platform 間の通信を有効にします。
- FEATURE_MQTT_DEFAULT_IMPL:Alibaba SDK で事前定義された MQTT クライアント実装を提供します。 MQTT クライアント実装に基づいて、TCP 接続を作成および確立し、TCP 接続を介してデータを送信するコードを記述する必要があります。
- FEATURE_MQTT_DIRECT:デバイスが接続できる IoT Platform エンドポイントを提供します。
FEATURE_SUPPORT_TLS オプションを選択することをお勧めします。このオプションを選択して、デバイスと IoT Platform 間で送信されるデータを暗号化できます。この例では、構成のワークロードを削減するために、このオプションは選択されていません。
他の機能を有効にする必要はありません。
選択した機能のソースコードを抽出する

Link SDK のコードファイルをコンパイル環境に統合する
前の手順で取得したコードファイルを出力ディレクトリからプロジェクトディレクトリにコピーします。次に、コンパイル環境または開発ツールを変更して、コードファイルをコンパイル環境に統合します。

ハードウェアアブストラクションレイヤー(HAL)関数を実装する
Link SDK は、さまざまなオペレーティングシステムで、またはオペレーティングシステムをサポートしていない MCU で実行するように設計されています。オペレーティングシステムに関連する操作は、実装する必要がある HAL 関数として定義されます。 OS は通信モジュールによって異なります。通信モジュールで実行する TCP 関連の操作も、実装する必要がある HAL 関数として定義されます。
すべての HAL 関数は、output/eng/wrappers/wrapper.c ファイルに格納されています。
OS 関連の HAL 関数
次の表に、実装する必要がある HAL 関数を示します。
| ** ** | 関数 | 説明 |
| 1 | HAL_Malloc | 指定されたメモリ長に基づいて、使用可能なメモリのブロックを占有し、ブロックの開始アドレスを返します。この関数は、C 標準ライブラリの malloc()関数に対応します。 |
| 2 | HAL_Free | 指定されたポインターによって示されるメモリ空間のブロックを解放します。この関数は、C 標準ライブラリの free()関数に対応します。 |
| 3 | HAL_Printf | 指定された文字列形式に基づいて、テキストを端末に出力します。この関数は、C 標準ライブラリの printf()関数に対応します。デバッグ環境でより良いデバッグ方法が利用できる場合は、この関数を実装する必要はありません。 |
| 4 | HAL_Snprintf | 端末ではなく、キャッシュ内の指定されたメモリブロックにテキストを出力します。この関数は、printf()関数に似ています。 |
| 5 | HAL_UptimeMs | uint64_t 値を返します。この値は、現在の時刻とデバイスが起動された時刻の間の経過ミリ秒数を示します。 |
| 6 | HAL_SleepMs | 指定されたミリ秒数に基づいて一定期間休止します。たとえば、10 を指定すると、関連するプログラムは 10 ミリ秒間休止します。 |
圧縮 SDK パッケージの wrappers/os ディレクトリには、HAL 関数の実装方法の例が含まれています。特定の例がオペレーティングシステムの要件を満たしている場合は、その例を使用できます。適切な例がない場合は、ビジネスシナリオに基づいて HAL 関数を実装する必要があります。
実装できる HAL 関数
モジュールでオペレーティングシステムが実行されていない場合、または Link SDK の MQTT API が複数のスレッドによって呼び出されていない場合は、wrapper.c ファイルの次の関数の定義を変更する必要はありません。モジュールでオペレーティングシステムが実行されており、Link SDK の MQTT API が複数のスレッドによって呼び出されている場合は、次の関数を実装する必要があります。
| ** ** | 関数 | 説明 |
| 1 | HAL_MutexCreate | ミューテックスを作成します。戻り値は HAL_MutexLock/Unlock に送信できます。 |
| 2 | HAL_MutexDestroy | ミューテックスを削除します。ミューテックスはリクエストパラメータで指定されます。 |
| 3 | HAL_MutexLock | ミューテックスを申請します。ミューテックスがスレッドによって使用されている場合、関数スレッドは休止状態のままです。そうでない場合、アプリケーションプロセスは続行されます。 |
| 4 | HAL_MutexUnlock | ミューテックスを解放します。ミューテックスを待機するために休止状態になっているスレッドは、ミューテックスを取得し、後続の操作を続行します。 |
| 5 | HAL_SemaphoreCreate | セマフォを作成します。戻り値は HAL_SemaphorePost/Wait に送信できます。 |
| 6 | HAL_SemaphoreDestroy | セマフォを削除します。セマフォはリクエストパラメータで指定されます。 |
| 7 | HAL_SemaphorePost | 指定されたセマフォの値をインクリメントし、他のスレッドの待機操作をキャンセルします。 |
| 8 | HAL_SemaphoreWait | 指定されたセマフォの値をインクリメントし、待機操作を実行します。 |
| 9 | HAL_ThreadCreate | リクエストパラメータに指定した値に基づいてスレッドを作成します。 |
TCP 関連の HAL 関数
MQTT 接続は TCP 経由で確立されます。モジュールプロバイダーは、次の TCP 関連の HAL 関数を実装する必要があります。
| シーケンス番号 | 関数 | 説明 |
| 1 | HAL_TCP_Establish | TCP 接続を確立します。ホストリクエストパラメータはドメイン名を指定します。ドメイン名を IP アドレスに変換する必要があります。戻り値は、TCP 接続のソケット番号です。 |
| 2 | HAL_TCP_Destroy | TCP 接続を閉じます。 HAL_TCP_Establish 関数の戻り値を HAL_TCP_Destroy 関数のリクエストパラメータの値として指定する必要があります。 HAL_TCP_Destroy 関数が 0 を返すと、呼び出しは成功です。 |
| 3 | HAL_TCP_Write | TCP 接続を介してデータを送信します。タイムアウト期間が関数に定義されています。関数は、指定されたデータがタイムアウト期間内に完全に送信されたかどうかに関係なく値を返します。データの送信中に TCP 接続が閉じられた場合、関数は負の数を返します。 |
| 4 | HAL_TCP_Read | 指定された期間内にデータを読み取り、データを返します。リクエストパラメータで、関数が読み取ることができるデータの最大長を指定できます。関数が TCP 接続を介して読み取ったデータの長さが最大長に達すると、関数はデータを返します。 |
プロダクト関連の HAL 関数
次の HAL 関数は、プロダクトの ID 検証情報を取得するために呼び出されます。デバイスメーカーは、デバイスにデバイスの ID 情報を書き込む方法、次の HAL 関数を使用して情報を取得する方法、および Link SDK で情報を指定する方法に関する手順を提供する必要があります。
| シーケンス番号 | 関数 | 説明 |
| 1 | HAL_GetProductKey | デバイスの ProductKey を取得します。 ProductKey は、デバイスのプロダクトモデルを識別するために使用されます。 |
| 2 | HAL_GetDeviceName | デバイスの DeviceName を取得します。 DeviceName は、デバイスを一意に識別するために使用されます。 |
| 3 | HAL_GetDeviceSecret | デバイスの DeviceSecret を取得します。 DeviceSecret は、デバイスのキーを識別するために使用されます。 |
実際のビジネスシナリオでプロダクトを構成する場合、上記のデータ項目はデバイスメーカーの AT コマンドによってモジュールに送信される必要があります。モジュールプロバイダーがテストデバイスをデバッグする場合、プロバイダーは上記の関数を呼び出すことによって、テストデバイスの ProductKey、DeviceName、および DeviceSecret を取得できます。
サンプルコードに基づいてプロダクト機能を実装する
モジュールプロバイダーは、出力ディレクトリの eng/examples/mqtt_example.c ファイルに基づいて機能をデバッグできます。デバイスメーカーは、ファイルを自分のプロジェクトにコピーし、ファイルを変更して機能を使用できます。
ファイル内のサンプルコードは、デバイスを IoT Platform に接続し、トピックをサブスクライブしてから、トピックにデータを送信するために使用されます。この場合、IoT Platform は、デバイスによって送信されたデータを、トピックをサブスクライブしているデバイスに送信します。次の図は、サンプルコードの動作方法を示しています。

IoT Platform コンソールで、トピックのデフォルトの権限を「サブスクライブ」から「パブリッシュとサブスクライブ」に変更する必要があります。

サンプルコードは main()関数から始まります。 main()関数の定義では、次のコードに示すように、プロダクト関連の HAL 関数が呼び出されて、プロダクトの ID 情報が取得されます。
int main(int argc, char *argv[])
{
void *pclient = NULL;
int res = 0;
int loop_cnt = 0;
iotx_mqtt_param_t mqtt_params;
HAL_GetProductKey(DEMO_PRODUCT_KEY);
HAL_GetDeviceName(DEMO_DEVICE_NAME);
HAL_GetDeviceSecret(DEMO_DEVICE_SECRET);
EXAMPLE_TRACE("mqtt example");
- HAL_Get で始まる上記の HAL 関数は、デバイスの証明書情報を取得するために呼び出されます。モジュールプロバイダーは、テストデバイスの証明書情報を指定できます。
次のコードは、ビジネス要件に基づいて MQTT 接続パラメータを構成する方法を示しています。
/* MQTT パラメータを初期化する */
memset(&mqtt_params, 0x0, sizeof(mqtt_params));
mqtt_params.port = sign_mqtt.port;
mqtt_params.host = sign_mqtt.hostname;
mqtt_params.client_id = sign_mqtt.clientid;
mqtt_params.username = sign_mqtt.username;
mqtt_params.password = sign_mqtt.password;
mqtt_params.request_timeout_ms = 2000;
mqtt_params.clean_session = 0;
mqtt_params.keepalive_interval_ms = 60000;
mqtt_params.read_buf_size = 1024;
mqtt_params.write_buf_size = 1024;
mqtt_params.handle_event.h_fp = example_event_handle;
mqtt_params.handle_event.pcontext = NULL;
pclient = IOT_MQTT_Construct(&mqtt_params);
Link SDK の IOT_MQTT_Construct()関数を呼び出して、デバイスを IoT Platform に接続します。関数が null 以外の値を返すと、IoT Platform への接続が確立されます。次に、example_subscribe 関数を呼び出して、トピックをサブスクライブします。
res = example_subscribe(pclient);

- デバイスメーカーは、トピックをサブスクライブし、プロダクトの設計に基づいて処理関数を実装する必要があります。
- 上記のサンプルコードでは、最初のオレンジ色の四角形のコードは、トピックが /$ProductKey/$DeviceName 形式であることを指定しています。 IoT Platform コンソールでプロダクトを作成すると、システムは上記の形式でトピックを自動的に作成します。
- 2 番目のオレンジ色の四角形のコードは、トピックに関する情報を指定します。
- 2 番目のオレンジ色の四角形のコードは、トピックをサブスクライブする方法と、トピックから受信したデータを処理するために呼び出される関数を指定します。
次のコードは、MQTT のパブリッシュ機能を使用してビジネスパケットを IoT Platform に送信する方法を示しています。
while (1) {
if (0 == loop_cnt % 20) {
example_publish(pclient);
}
IOT_MQTT_Yield(pclient, 200);
loop_cnt += 1;
}
- 上記のサンプルコードは、定期的に固定メッセージを IoT Platform に送信します。デバイスメーカーは、自社プロダクトの機能に基づいて、必要なデータのみを IoT Platform に送信することをお勧めします。
- 無効なデータが定期的に IoT Platform に送信されないようにするには、main()関数から example_publish(pclient) 文を削除できます。
- Link SDK の IOT_MQTT_Yield 関数は、MQTT ブローカーからデータを受信するために呼び出されます。値 200 は、関数がデータを受信する前に 200 ミリ秒待機する必要があることを示します。メッセージの数が多い場合、またはレイテンシ要件が高い場合は、より小さい値を指定できます。

上記の図では、最初のオレンジ色の四角形のコードは、送信するメッセージの内容を指定します。 2 番目のオレンジ色の四角形のコードは、Link SDK の関数を呼び出して、メッセージを指定されたトピックに送信します。
モジュールプロバイダー ID とモジュールモデルをアップロードする
モジュールプロバイダーが IoT Platform でモジュールを検証する場合、モジュールプロバイダーはモジュールプロバイダー ID とモジュールのモデルを送信する必要があります。これにより、IoT Platform は、モジュールプロバイダー ID またはモジュールモデルによって IoT Platform に接続されているデバイスの数を取得できます。
Link SDK を統合する前に、次のテンプレートに基づいてメッセージを送信して、Alibaba Cloud に連絡して、モジュールプロバイダー ID とモジュールモデルを取得してください。詳細については、「お問い合わせ」をご覧ください。
件名:Link SDK を使用してデバイスを接続する - モジュールまたはチップモデルを申請するモジュールが 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 パラメータの値を含むメッセージを送信します。*/
res = IOT_MQTT_Publish(pclient, topic, &topic_msg);
if (res < 0) {
return -1;
}
return 0;
}
機能をデバッグする
次のスクリーンショットは、mqtt_example.c ファイルを変更して実行した後の結果に基づいて提供されています。
デバイスが IoT Platform に接続されているかどうかを確認する
デフォルトでは、デバイスには /${productKey}/${deviceName}/get トピックに対するサブスクライブ権限が付与されます。メッセージが IoT Platform に送信された後にメッセージがドロップされないようにするには、トピックの権限を「サブスクライブとパブリッシュ」に変更することをお勧めします。これにより、サンプルプログラムはエラーなしで想定どおりに実行できます。

デバイスから IoT Platform にデータが送信されているかどうかを確認する

前の図は、メッセージが送信されたトピックを示しています。メッセージの内容は表示されません。
デバイスが IoT Platform からデータを受信しているかどうかを確認する


AT コマンドを実装する
モジュールプロバイダーは、モジュールでカスタム開発を実行するために使用できる開発環境を提供しません。代わりに、モジュールプロバイダーは外部 MCU を接続し、プロダクトのビジネスロジックは MCU で実行されます。この場合、モジュールプロバイダーは、MCU によって呼び出すことができる AT コマンドを提供する必要があります。ほとんどの場合、モジュールは TCP のみをサポートします。 MQTT 接続の構成、接続の確立、接続のクローズ、メッセージのサブスクライブ、メッセージのパブリッシュを実行できる API 操作を提供する必要があります。
次の表に、推奨される AT コマンドを示します。モジュールプロバイダーは、複数の AT コマンドを 1 つの AT コマンドに結合したり、1 つの AT コマンドを複数の AT コマンドに分割したりできます。モジュールプロバイダーは、AT コマンドのカスタム形式を定義できます。
| コマンド | 説明 |
| デバイスの ID 情報を指定する | デバイスの ProductKey、ProductSecret、DeviceName、および DeviceSecret を指定します。 |
| IoT Platform エンドポイントを指定する | IoT Platform は、中国本土、米国、日本など、複数のリージョンで利用できます。 MCU が接続できる IoT Platform エンドポイントに関する情報を指定できます。 |
| MQTT 接続を確立する | Alibaba Cloud MQTT ブローカーへの接続を確立します。 AT コマンドを実行して、MQTT クリーンセッション、キープアライブ間隔、およびリクエストタイムアウト期間を指定できます。 |
| MQTT 接続を閉じる | IoT Platform への MQTT 接続を閉じます。 |
| トピックをサブスクライブする | メッセージを受信するためにトピックをサブスクライブします。 |
| トピックのサブスクライブを解除する | メッセージの受信を停止するためにトピックのサブスクライブを解除します。 |
| トピックにデータを送信する | トピックにデータを送信します。 |
MCU が AT コマンドを実行してデバイスの ID 情報をモジュールに送信する場合、情報をグローバル変数の値として指定することをお勧めします。これにより、HAL_GetProductKey、HAL_GetDeviceName、および HAL_GetDeviceSecret はグローバル変数を返すことができ、サンプルコードを変更する必要はありません。