ESP-IDFを使ってみる

https通信


esp-idfには多数のサンプルが有りますが、こ ちらにhttp/httpsクライアントのサンプルが有ります。
httpを使う場合は特に難しことは何もありませんが、httpsを使う場合、ルート証明書が必要になります。
httpsの使い方が分かったので紹介します。
こ の部分でurlやevent handlerを登録しますが、同時に以下のコードでルート証明書(文字列としてのPEM形式)を登録します。

.cert_pem = howsmyssl_com_root_cert_pem_start

ルート証明書の取得手順はこ ちらに記載されています。
opensslコマンドを実行するとずらずらとテキストが表示されますが、使うのは下の方のルート証明書です。
このルート証明書をコピペして、適当なファイルで保存します。
この手順は探した限り、どのドキュメントにも書かれてなくて、ソースのコメントとして書かれているだけです。

/* Root cert for howsmyssl.com, taken from howsmyssl_com_root_cert.pem
   The PEM file was extracted from the output of this command:
   openssl s_client -showcerts -connect www.howsmyssl.com:443 </dev/null
   The CA root cert is the last cert given in the chain of certs.
   To embed it in the app binary, the PEM file is named
   in the component.mk COMPONENT_EMBED_TXTFILES variable.
*/


howsmyssl_com_root_cert.pemから取得したhowsmyssl.comのルート証明書
PEMファイルは、このコマンドの出力から抽出されました。
  openssl s_client -showcerts -connect www.howsmyssl.com:443 </dev/null
CAルート証明書は、証明書チェーンの最後の証明書です。
アプリバイナリに埋め込むために、PEMファイルはcomponent.mk COMPONENT_EMBED_TXTFILES変数で名前が付けられます。

httpsのサンプルのルート証明書は、こ のようなファイルになっています。

次に、CMakeLists.txtにこ ちらのコードを追加します。
指定するのはルート証明書のファイル名です。
これでビルド時に、ルート証明書がNULL終端の文字列としてコードに埋め込まれます。
この手順も、先ほどのソースのコメントをよく読まないと分かりません。

最後に、こ の2行を追加して、ルート証明書へのポインターを定義します。
ポインターはファイルの開始位置と、ファイルの終了位置の2つを定義していますが、NULL終端で埋め込まれるので、
開始位置を指定することで文字列として扱われます。
これでhttps通信ができるようになります。

こ ちらにhttpのドキュメントが有りますが、ルート証明書の取得・登録方法まで書かれていません。

コードへの埋め込みは2つの方法が有ります。
以下の様にするとNULL終端なしでファイルをコードに埋め込みます。
バイナリファイルを埋め込む時に使います。
ファイルサイズは[ファイルの終了位置−ファイルの開始位置]で求めることができます。
idf_component_register(...
                       EMBED_FILES server_root_cert.der)

以下の様にするとNULL終端の文字列としてファイルをコードに埋め込みます。
テキストファイルを埋め込む時に使います。
idf_component_register(...
                       EMBED_TXTFILES server_root_cert.pem)



もう一つ埋め込みネタを紹介します。

こちら
のサンプルにはJPEG Decorderが含まれていますが、JSONライブラリと同様に(というかそれ以上に)資料が有りません。
こ のソースファイルがJPEG Decorderですが、コードに埋め込まれたJPEGデータしかデコードできません。

上のルート証明書の埋め込みと同様に、component.mkで埋め込むJPEGファイルを指定し、ビルドと同時にコードにJPEGイメージを 埋め込んで、
埋め込まれたJPEGイメージのポインターをこ ちらで定義しています。

JPEGイメージのデコードはこ の関数を呼び出すだけです。
サンプルではこ の関数でデコードを行い、デコードした結果をこ の関数で読み込んでいます。
pretty_effect_calc_lines()は少し難解な関数で、frameには何回目の描画を行うかの回数が渡ってきます。
n回目の時は三角関数を使って、読み込み位置を少しずらすことで、アニメーションの表示を行っています。
最初に見たときは、なんで三角関数が必要なのかさっぱりわかりませんでした。



HTMLやCSSの様に、静的なテキストファイルをファームの中で読み込む場合、spiffsにファイルを置いて実行時に読み込むよりも、コード に埋め込んだ方 がはるかに高速に動作します。
巨大なテキストファイルになると、その差は歴然です。
但し、コードに埋め込むと、プログラムの一部となるため、その分だけメモリーを消費します。
アプリケーションのためのパーティション(factoryパーティション)のデフォルトサイズは1MByteで、調子に乗ってどんどんファイルを 埋め込むと、これを超えて以下のエ ラーとなります。
マイコンで1MByteのコードを書くのはメチャクチャ大変ですが、今回初めて超えました。
Error: app partition is too small for binary mqtt-client.bin size 0x104010:
  - Part 'factory' 0/0 @ 0x10000 size 0x100000 (overflow 0x4010)

大きいアプリをビルドする場合は、カスタムパーティションファイルを作成し、より大きなサイズを指定します。
# Name,   Type, SubType, Offset,  Size, Flags
# Note: if you change the phy_init or app partition offset, make sure to change the offset in Kconfig.projbuild
nvs,      data, nvs,     0x9000,  0x6000,
phy_init, data, phy,     0xf000,  0x1000,
#factory,  app,  factory, 0x10000, 1M,
factory,  app,  factory, 0x10000, 2M,

これで、アプリケーションのためのパーティションサイズは2MByteになります。
ビルドして実行すると、factoryパーテイションのサイズが2MByteになっていることが分かります。
I (60) boot: Partition Table:
I (64) boot: ## Label            Usage          Type ST Offset   Length
I (71) boot:  0 nvs              WiFi data        01 02 00009000 00006000
I (78) boot:  1 phy_init         RF data          01 01 0000f000 00001000
I (86) boot:  2 factory          factory app      00 00 00010000 00200000
I (93) boot: End of partition table

続く...