- ESP-IDF 6.0 では cJSON・esp-mqtt などが本体同梱でなくなり、公式の ESP Component Registry から取得する方式になりました
- 使い方は
idf_component.ymlに依存を1行書くだけ。ビルド時にコンポーネントマネージャが自動で取得し、dependencies.lockでバージョンが固定されます - 本記事は ESP-IDF 6.0.2+ESP32-S3 実機で、Wi-Fi 接続 → cJSON で JSON 組み立て → HTTP POST 成功までを実際に通した記録です
🧭 はじめに:#include "cJSON.h" が通らない?——それ、6.0 の仕様です
ESP-IDF で JSON を扱うといえば cJSON です。v5.x までは本体に同梱されていたので、何も考えずに #include "cJSON.h" と書けば使えました。当サイトの ESP32-S3 × ESP-IDF|cJSONとHTTP ClientでJSONをPOST送信 も、その時代の書き方です。
ESP-IDF 6.0 では、これがビルドエラーになります。 cJSON が本体から外され、ESP Component Registry(コンポーネントレジストリ)から取得する方式に変わったからです。
と聞くと面倒になったように感じますが、実際にやってみると逆でした。idf_component.yml というファイルに依存を1行書くだけで、ビルド時に自動で取ってきてくれる。npm(Node.js)や cargo(Rust)を使ったことがあれば、あの感覚です。組み込み開発にも、ようやく「依存管理」の時代が来た——本記事では、それを ESP32-S3 実機で最後まで通して確かめます。
この記事は ESP-IDF 6.0 シリーズの実践編です。6.0 で何が変わったかの全体像は ESP-IDF 6.0 移行ガイド、6.0 環境の作り方(複数バージョン共存)は EIM の使い方 を先にどうぞ。
ソースコード全体は GitHub で公開しています(MIT License)。
ramtuc/esp-idf6-registry-http-post(GitHub)
💡 ESP Component Registry とは
ESP Component Registry(components.espressif.com)は、Espressif が運営する ESP-IDF 用コンポーネントの公式配布サイトです。Espressif 製・サードパーティ製のライブラリが登録されていて、プロジェクトの idf_component.yml(マニフェストファイル)に名前とバージョン制約を書くと、IDF Component Manager がビルド時に自動でダウンロード・組み込みします。
- npm でいう package.json =
idf_component.yml/node_modules =managed_components//package-lock.json =dependencies.lock - レジストリ自体は v5.x 時代からありましたが、6.0 で「同梱コンポーネントの移管先」となり、事実上の必須インフラになりました
6.0 で本体からレジストリへ移管された主なコンポーネントは次のとおりです(詳細は移行ガイドの該当節を参照)。
| コンポーネント | 6.0 での扱い |
|---|---|
cJSON |
レジストリの espressif/cjson へ(本記事で実演) |
esp-mqtt |
コンポーネントマネージャ経由での取得へ |
wifi_provisioning |
network_provisioning に名称変更のうえレジストリへ |
なぜ外に出すのか。公式の説明を移行の文脈で読むと、本体のスリム化とコンポーネント単位の独立した更新が軸です。本体のリリースを待たずにライブラリ側だけ更新できるのは、利用者にとっても悪い話ではありません。
🗺️ 作るもの:Wi-Fi 接続 → JSON 組み立て → HTTP POST
やることは IoT の基本形そのものです。ESP32-S3 が Wi-Fi に接続し、cJSON でペイロードを組み、公開エコーサーバ(postman-echo.com)へ HTTP POST して、返ってきたレスポンスを確認します。
(espressif/cjson を1行宣言)"] --> CM["IDF Component Manager
(idf.py 実行時に自動で動く)"] CM --> REG["ESP Component Registry
components.espressif.com"] REG --> MC["managed_components/espressif__cjson
(プロジェクト内に取得)"] CM --> LOCK["dependencies.lock
(解決したバージョンを固定)"] MC --> APP["アプリ:Wi-Fi 接続 → cJSON で JSON → esp_http_client で POST"]
プロジェクト構成は最小です。
http-post-registry/
├── CMakeLists.txt
└── main/
├── CMakeLists.txt
├── idf_component.yml ← 今回の主役
├── Kconfig.projbuild ← SSID/パスワードを menuconfig 項目化
└── main.c
📦 核心:idf_component.yml を書く——そして取得される瞬間
主役のファイルはこれだけです。全文を載せます。
## IDF Component Manager マニフェスト
## 6.0 では cJSON が本体同梱でなくなったため、レジストリから取得する
dependencies:
idf: ">=6.0"
espressif/cjson: "^1.7.19~2"
- 置き場所は
main/コンポーネントの直下です(プロジェクト直下ではない点に注意) espressif/cjsonが「名前空間/コンポーネント名」。バージョン制約^1.7.19~2は「1.7.19~2 以上・メジャー 1 のまま」の意味で、レジストリのコンポーネントページに掲載されている表記をそのまま使えます- 依存の追加はコマンドでもできます:
idf.py add-dependency "espressif/cjson^1.7.19~2"
この状態で idf.py set-target esp32s3(または reconfigure)を実行すると、コンポーネントマネージャが動きます。実際のログがこちら。
NOTICE: Dependencies lock doesn't exist, solving dependencies.
NOTICE: Updating lock file at D:\tmp\esp-idf-6-migration\http-post-registry\dependencies.lock
NOTICE: Processing 2 dependencies:
NOTICE: [1/2] espressif/cjson (1.7.19~2)
NOTICE: [2/2] idf (6.0.2)
実行後、プロジェクトに2つのものが増えています。
managed_components/espressif__cjson/— レジストリから取得された cJSON の実体。これでソースの#include "cJSON.h"がそのまま通りますdependencies.lock— 解決結果のバージョンを固定するロックファイル。別のマシンでも同じバージョンが再現されます(npm の lock ファイルと同じ発想)
同じ configure ログに Component directory .../esp-idf/components/mqtt does not contain a CMakeLists.txt file. No component will be added という行が出ます。6.0 のソースツリーでは mqtt の置き場所が空になっていて、「同梱をやめてレジストリへ」が実際のディレクトリ構造にも表れています。MQTT を使うプロジェクトを 6.0 に移すときは、cJSON と同じ要領で idf_component.yml に依存を書くことになります。
managed_components/ の中身はコンポーネントマネージャの管理物です。ここを直接編集すると、次の解決時にハッシュ不一致で怒られます。生成物なので、Git 管理からも外すのが基本です(dependencies.lock は逆にコミットする——ここも npm と同じ流儀)。
🔌 コード:Wi-Fi 接続と HTTP POST(6.0 の作法で)
コードは素直な IoT の基本形です。全文は GitHub リポジトリ にあります——クローンして idf.py menuconfig で Wi-Fi の SSID/パスワードを設定すれば、README の手順どおりそのまま実機で動かせます。ここでは要点を抜粋します。
Wi-Fi STA 接続(イベントグループで完了待ち)
static void wifi_event_handler(void *arg, esp_event_base_t base, int32_t id, void *data)
{
if (base == WIFI_EVENT && id == WIFI_EVENT_STA_START) {
esp_wifi_connect();
} else if (base == WIFI_EVENT && id == WIFI_EVENT_STA_DISCONNECTED) {
if (s_retry_num < MAX_RETRY) {
esp_wifi_connect();
s_retry_num++;
} else {
xEventGroupSetBits(s_wifi_events, WIFI_FAIL_BIT);
}
} else if (base == IP_EVENT && id == IP_EVENT_STA_GOT_IP) {
xEventGroupSetBits(s_wifi_events, WIFI_CONNECTED_BIT);
}
}
SSID とパスワードはコードに直書きせず、Kconfig.projbuild で menuconfig の項目にして sdkconfig 側へ逃がしています。認証情報をソースから分離しておくと、コードを記事や Git に出すときに事故が起きません。
config APP_WIFI_SSID
string "WiFi SSID"
default "changeme"
cJSON でペイロードを組んで POST
/* レジストリから取得した cJSON で JSON ペイロードを組む */
cJSON *root = cJSON_CreateObject();
cJSON_AddStringToObject(root, "device", "esp32-s3");
cJSON_AddStringToObject(root, "idf", IDF_VER);
cJSON_AddNumberToObject(root, "free_heap", (double)esp_get_free_heap_size());
char *payload = cJSON_PrintUnformatted(root);
esp_http_client_config_t config = {
.url = "http://postman-echo.com/post",
.event_handler = http_event_handler,
};
esp_http_client_handle_t client = esp_http_client_init(&config);
esp_http_client_set_method(client, HTTP_METHOD_POST);
esp_http_client_set_header(client, "Content-Type", "application/json");
esp_http_client_set_post_field(client, payload, strlen(payload));
esp_err_t err = esp_http_client_perform(client);
判定は esp_http_client_perform() の戻り値(通信としての成否)と HTTP ステータスコード(サーバの応答)を別々に見ます。公開エコーサーバは混雑で一時的に 5xx を返すことがあるため、実装では 2xx 以外に備えた軽いリトライも入れています。
cJSON の API は v5.x 時代とまったく同じです。変わったのは「どこから来るか」だけで、書き味は何も変わりません。esp_http_client は 6.0 でも本体同梱のままなので、こちらは追加の依存宣言も不要です。
なお main/CMakeLists.txt の PRIV_REQUIRES に注意点がひとつ。使用する本体コンポーネント(esp_wifi・esp_http_client など)は明示しますが、cJSON は書きません。idf_component.yml の依存はコンポーネントマネージャが自動で配線してくれるからです。
🧪 実機実録:ビルド → 書き込み → POST 成功まで
ここからは、この環境(EIM で導入した v6.0.2+ESP32-S3 実機)で実際に通した記録です。
ビルドと書き込み
eim run "idf.py -C <プロジェクト> build" v6.0.2
eim run "idf.py -C <プロジェクト> -p COM5 flash" v6.0.2
ビルドは約 1,070 ステップで、バイナリは 893,760 バイト(既定の 1MB アプリパーティションの 85%)。Wi-Fi・TCP/IP・HTTP クライアントが乗ると、hello_world(約142KB)の6倍のサイズ感になります。書き込みは3イメージすべて Hash of data verified で完了しました。
シリアルログ:起動から POST 成功まで約2秒
リセット後のシリアル出力の要点です(SSID・MAC アドレス・IP はマスクしています)。
I (424) post_registry: connecting to Wi-Fi...
I (734) wifi:connected with <SSIDマスク>, aid = 21, channel 5, BW20
I (734) wifi:security: WPA2-PSK, phy: bgn, rssi: -37
I (1784) esp_netif_handlers: sta ip: 192.168.0.xxx, mask: 255.255.255.0
I (1784) post_registry: Wi-Fi connected
I (1784) post_registry: POST payload: {"device":"esp32-s3","idf":"v6.0.2","free_heap":287456}
I (2094) post_registry: HTTP POST status = 200 (attempt 1)
I (2094) post_registry: response body (380 bytes):
{"args":{},"data":{"device":"esp32-s3","idf":"v6.0.2","free_heap":287456},
"headers":{...,"content-type":"application/json","user-agent":"ESP32 HTTP Client/1.0",...},
"json":{"device":"esp32-s3","idf":"v6.0.2","free_heap":287456},
"url":"https://postman-echo.com/post"}
I (2124) post_registry: done
電源投入から POST 完了まで約 2.1 秒。エコーサーバのレスポンスの json フィールドに、cJSON で組んだペイロードがそっくりそのまま返ってきているのが分かります。レジストリから取得した cJSON が実機できちんと仕事をした、何よりの証拠です。
✅ まとめ
- ESP-IDF 6.0 では cJSON・esp-mqtt などが本体同梱でなくなり、ESP Component Registry から取得する方式になりました
- 使い方は
main/idf_component.ymlに依存を1行。ビルド時にmanaged_components/へ自動取得され、dependencies.lockで再現性が担保されます——package.json / node_modules / lock ファイルの関係そのままです - cJSON の API は v5.x と同一。変わるのは取得経路だけで、コードの書き味は変わりません
- 実機(ESP32-S3+v6.0.2)で Wi-Fi 接続 → JSON 組み立て → HTTP POST → レスポンス確認まで一通り成立しました
- 「本体のリリースを待たずにライブラリだけ更新できる」体制は、使う側にもメリットがあります。6.0 移行の"面倒な変更"に見えて、実は開発体験の底上げでした
❓ よくある質問(FAQ)
Q. v5.x のプロジェクトを 6.0 に移したら cJSON でビルドエラーになりました。最短の直し方は?
A. main/idf_component.yml を作成(既にあれば追記)して espressif/cjson: "^1.7.19~2" を依存に追加し、idf.py reconfigure を実行してください。managed_components/ に取得されれば、既存の #include "cJSON.h" はそのまま通ります。ソースコードの変更は不要です。
Q. managed_components や dependencies.lock は Git にコミットすべきですか?
A. managed_components/ は生成物なのでコミットせず(.gitignore に追加)、dependencies.lock はコミットします。ロックファイルを共有すれば、チームや CI でも同じバージョンの依存が再現されます。
Q. レジストリにないライブラリを使いたいときは?
A. 従来どおり components/ ディレクトリに手動でソースを置く方法も引き続き使えます。レジストリは「同梱の置き換え+配布の標準化」であって、手動コンポーネントを禁止するものではありません。
Q. オフライン環境ではビルドできなくなりますか?
A. 一度取得すれば managed_components/ はローカルに残るため、以後の再ビルドに通信は不要です。初回解決だけネットワークが必要になります。
関連記事
- ESP32-S3 × ESP-IDF|cJSONとHTTP ClientでJSONをPOST送信:v5.x 時代の同じテーマ。cJSON が同梱だった頃の書き方との違いがよく分かります
- ESP-IDF 6.0 移行ガイド|レガシードライバ全廃と破壊的変更の要点:6.0 で何が変わったかの全体像。コンポーネント移管はその一部です
- EIM(ESP-IDF Installation Manager)の使い方|複数バージョン共存で変わる ESP32 開発環境:本記事のビルド環境(v6.0.2)の作り方
- ESP32 シリーズの選び方|S3・C3・C6・H2・P4 の違いと使い分け:どのチップで作るかを用途から選ぶ