Arduino – ESP32 WiFiClientSecure ライブラリで、安定して https ( SSL )記事をGETする方法

記事公開日:2017年7月25日
最終修正日:2017年8月14日

スポンサーリンク

こんばんは。

今回こそは、Web記事4つ連続取得したミニ電光掲示板を紹介する予定でしたが、その前に Arduino core for ESP32 の WiFiClientSecure ライブラリの使い方を紹介しておこうと思います。

なかなかこれは Sample スケッチを見ただけでは良く分からないことが多いんですよね。
しかも、ネット上ではWiFiClientSecure を使った解説は殆どありませんし・・・。

でも、前回前々回の記事で勉強したことを頭に入れておくと、いろいろと細かいことが分かって来ました。

そして、今回は Yahoo! Japan RSS ニュースサイトの https ( SSL ) 記事に関しては、かなり安定して GET できるようになりました。

以前はたまに記事を取得できない時がありましたが、今回はほぼ100%取得できるようになりました。
これには、プログラム(スケッチ)の組み方に少々工夫が必要で、今回はその方法を紹介したいと思います。

そして、よく分からなかった ルート証明書 ( root_ca ) についてもかなり分かって来ましたので、それも紹介してみたいと思います。

この記事および自作ソースコードの公開について、Yahoo! Japan さんにお問い合わせして、趣味や研究範囲と判断でき、問題無いとの回答を得ております。
(2017/8/11)

もし、誤っていたらコメント投稿欄等でご連絡いただけると助かります。

使用するもの

以下のESP-WROOM-32 ( ESP32 ) 開発ボードを使います。
日本の電波法をクリアした、いわゆる技適取得済みの Wi-Fi 、Bluetooth搭載マイコンボードです。

ESPr Developer 32 ( スイッチサイエンス )

USB電源のソフトスタート機能や、FTDI社製 USB-シリアル変換チップを搭載した、日本製 ESP-WROOM-32 開発ボードです。

ESPr_Developer32_01

ESPr® Developer 32

当ブログとしてもお勧めの日本製ボードです。
これをレビューした以下の記事も参照してみてください。

ESPr Developer 32 ( スイッチサイエンス製 ) を使ってみました

ESP32-DevKitC ( Espressif )

ESP32 チップの本家中国メーカー、Espressif 社純正の開発ボードです。
秋月電子通商さんで販売しています。

ESP32-DevKitC ESP-WROOM-32開発ボード

Amazon.co.jp でも販売しています。

Arduino core for ESP32 をインストールしておく

Arduino IDE は 1.8.3 以上を使用してください。

Arduino core for ESP32 のインストール方法は以下の記事を参照してください。

Arduino core for the ESP32 のインストール方法

WiFiClientSecure 関連ライブラリを ESP-IDF で修正して上書きコピーする

Arduino core for ESP32 の WiFiClientSecure ライブラリは、デフォルトで使用するとハングアップ(フリーズ)します。
SSL ( https )Webページから 数十回~数百回 GET リクエストを繰り返すと、固まってマイコンが動かなくなります。
GitHub の issue で投げかけていますが、なかなか修正してくれませんので、以下の記事を参照して、mbedtls ライブラリを修正してください。
ちょっと面倒ですが・・・。

2017/8/2に修正されました。libmbedtls.a ファイルと main.cpp のスタックサイズも修正されました。

Arduino – ESP32 WiFiClientSecure ライブラリのハングアップ問題がついに解決!

SSL ( https ) Webページについて

世の中のセキュリティー向上の風潮と、Google が SSL ページを優先して検索画面の上位に表示させる方向性を示したことにより、最近多くの Web サイトが SSL 化されてきました。

当ブログでも随分前にお金を払って既に SSL 化しています。

下図の様に、Google Chrome の場合は URL アドレス入力欄に緑色の鍵アイコンが表示されて、「保護された通信」と出ていれば、SSL 対応ページということになります。

ESP32_WiFiClientSecure20

正直、私はあまり SSL 通信に詳しくはないのですが、Webサイトを SSL化するということについてザッと簡単に説明してみます。

まず、SSL専用サーバーにWebページ全体を移行し、お金を払って SSL 認証局 ( VeriSignとか、GeoTrustとか) に信頼あるサイトとして証明してもらい、証明書を発行してもらいます。
そして、クライアントがブラウザでWebページを見ようとするときに、サーバーから暗号化された証明書をブラウザに送ります。

そして、ブラウザにはルート証明書が予め保存してあり、それと送られてきたサーバーの証明書とを照合することによって、そのサイトは信頼あるサイトかどうかを判断しています。
そして、公開鍵、秘密鍵、共通鍵を使ってブラウザとサーバーとの間で通信を暗号化、復号化しているという感じです。
私もこの通信について突っ込まれると、まだちゃんと答えられないことが多いのですが、この辺についてはネットで情報が沢山あるので調べてみて下さい。

普段、ブラウザでネットサーフィンしている分には、殆どストレス無しで観閲できますよね。
これって意外と不思議と思いませんか?
そして、ブラウザに予めルート証明書が登録してあるということはどういうことでしょうか?

これはつまり、ブラウザメーカー( Microsoft や Google , Apple 等)が SSL認証局や証明書を厳密に審査して、合格した認証機関証明書だけをブラウザに予め保存しておいてあるということだそうです。

登録してある証明書は Google Chrome では下図の様に設定画面で確認することができます。

ESP32_WiFiClientSecure21

次に下図の様に設定の三本線をクリックします。

ESP32_WiFiClientSecure22

そして、下図の様に「詳細設定」を選択して、「プライバシーとセキュリティー」をクリックします。

ESP32_WiFiClientSecure23

次に、下図の様に「証明書の管理」をクリックします。

ESP32_WiFiClientSecure24

すると、証明書のウィンドウが開くので、「信頼されたルート証明機関」タブをクリックすると、予めブラウザに登録してあるルート証明書の一覧を見ることができます。

ESP32_WiFiClientSecure25

ここにある証明書と同じ証明書があれば、信頼あるサイトとしてブラウザが判断できるわけです。
あとは中間証明機関とかいろいろありますが、長くなるのでここでは割愛します。

その他、ブラウザとサーバー間で公開鍵、秘密鍵、共通鍵のやり取りを高速で行ってデータを暗号化したり復号したりしています。
ですから、SSL 通信というのは、暗号化や復号化などの厖大な文字列やデータをやり取りしているので、これをマイコンで通信しようとすると、メモリの面でかなり厳しいということが分かると思います。

以上、ザッと簡単な SSL通信の概要でした。

SSL認証局(ルート証明書)を取得する

では、ESP32 ( ESP-WROOM-32 )マイコンで SSL ( https )ページを取得するには、ブラウザと同じように公開鍵を含んだルート証明書をマイコンに保存しておかねばなりません。
そこで、Yahoo! Japan RSS ニュースサイトのルート証明書を取得してみたいと思います。

Yahoo! Japan と言えば、誰もが信頼できるサイトと言えますね。
つまり、私個人として、このサイトは信頼できるサイトとして既に審査合格です。
そこで使っているルート証明書を ESP32 ( ESP-WROOM-32 ) に登録しておけば、Yahoo! Japan を信頼あるサイトとして照合できるわけです。

当ブログの過去の記事でも沢山紹介しましたが、Yahoo! Japan RSS サイトというのは、テキストベースの記事で様々なニュースの見出しを提供している、電子工作的にはとても便利なサイトです。
ニュースの詳しい内容を見ることはできませんが、電子工作で電光掲示板に表示させるくらいならば十分です。
私的には、ニュース記事の見出し(記事の題名)だけでもある程度把握できるので、とても重宝しています。
もし、もっと詳しい内容を見たければ、スマホやパソコンでそのサイトを訪問すれば良いわけですから・・・。

因みに、このサイトの利用は個人使用の範囲では無料ですが、それ以上や商用利用については Yahoo! Japan さんへ直接お問い合わせください。

では、まず以下のように、Arduino IDE のWiFiClientSecureサンプルスケッチを開いてみて下さい。

ESP32_WiFiClientSecure01

すると、こんな感じにtest_root_ca なるものがあります。

ESP32_WiFiClientSecure02

これが、先ほど説明した認証局が証明している暗号化されたルート証明書です。
因みに、この証明書は Yahoo! Japan RSS サイトのルート証明書ではないので使えません。

Yahoo! Japan RSS サイトの場合は、現時点ではこの証明書が無くても記事を取得できますが、将来的にこれが無いと取得できなくなる可能性もあるので、設定しておいた方が良いでしょう。

では、Yahoo! Japan RSS サイトのルート証明書を取得する方法を説明します。
パソコンのブラウザによって取得方法が異なります。
(Windows10 の場合で説明します)

Google Chrome の場合

まず、Google Chrome を起動し、以下のYahoo! Japan RSSサイトを開いて、右上端の点々をクリックします。

https://headlines.yahoo.co.jp/rss/list

ESP32_WiFiClientSecure03

次に「その他のツール」→「デベロッパーツール」をクリックします。

ESP32_WiFiClientSecure04

次に、下図の様に 「Security 」タブを選択後、「View certificate」をクリックします。

ESP32_WiFiClientSecure05

すると、下図の様にウィンドウが出ますので、「証明のパス」タブを選択し、一番上の証明書を選択します。
ここでは、DigiCert Baltimore Root になります。
その後、「証明書の表示」ボタンをクリックします。

ESP32_WiFiClientSecure06

すると、下図の様に同じようなウィンドウがもう一つ表示されます。
これが、ルート証明書のウィンドウになります。
前のウィンドウと間違えやすいので気を付けてください。

そしたら、下図の様に「詳細」タブを選択し、「ファイルにコピー」ボタンをクリックします。

ESP32_WiFiClientSecure07

すると、下図の様な表示が出るので、「次へ」をクリックします。

ESP32_WiFiClientSecure08

次に、エクスポートするファイル形式は Base 64 エンコードを選択して、「次へ」をクリックしてください。

ESP32_WiFiClientSecure09

すると、下図の様になるので、好きなファイル名を入力し、「参照」で好きなフォルダを指定します。
良ければ、「次へ」をクリック

ESP32_WiFiClientSecure10

すると、下図の様な表示になるので、ここは何も選択せず、そのまま「完了」をクリックして終了です。

ESP32_WiFiClientSecure11

そうすると、指定したフォルダにこんな感じでルート証明書ファイルができています。

ESP32_WiFiClientSecure12

これをテキストエディタで開きます。
すると、下図の様に Arduino IDE サンプルスケッチにあったような暗号化されたルート証明書になっていることがわかると思います。
この中には認証機関や公開キー等の情報が暗号化されて詰まっています。

ESP32_WiFiClientSecure13

これを、Arduino IDE にコピペして、サンプルスケッチにあるような書式に変更すれば良いわけです。

Windows Edge の場合

Windows10 のブラウザ、Edge の場合は方法がちょっと異なります。
なぜか、Windows Edge では SSL サイトのルート証明書を見ることが出来ません。
これは、セキュリティーを強化するためなのかも知れませんが、ユーザー側としてはサイトが信頼できるかどうか確認するためにも、閲覧できるようにしてもらいたいですね。

では、どうするかというと、Internet Explorer で見ることになります。

まず、Edge で Yahoo! Japan ニュース RSSサイトを開き、下図の様なところをクリックします。

ESP32_WiFiClientSecure14

次に下図の様に「Internet Explorer」で開く をクリックします。

ESP32_WiFiClientSecure15

次に、下図の様に Internet Explorer の鍵アイコンをクリックします。

ESP32_WiFiClientSecure16

次に、下図の様なウィンドウが出ますので、「証明書の表示」をクリックします。

ESP32_WiFiClientSecure17

すると、このように表示されるので、あとは先に説明した Google Chrome と同じ方法でルート証明書を取得すれば良いです。

ESP32_WiFiClientSecure18

以上、Yahoo! Japan RSS ニュースサイトのルート証明書の取得方法でした。

スケッチの入力

では、Arduino IDE に以下のスケッチを入力してみてください。

SSL ( https )ページを定期的に安定して文字列を取得するには、微妙な細かいプログラムノウハウがありますので、解説をよく読んでみてください。

因みに、このプログラムは無保証です。このプログラムが原因で起きたいかなるトラブルも当方では一切責任を負いませんので予めご了承ください。

#include <WiFiClientSecure.h>

const char* ssid = "xxxx"; //ご自分のルーターのSSIDに書き換えてください。
const char* password = "xxxx"; //ご自分のルーターのパスワードに書き換えてください

//Yahoo! Japan RSSニュース、ルート証明書
const char* yahoo_root_ca= \
  "-----BEGIN CERTIFICATE-----\n" \
  "MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJJ\n" \
  "RTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYD\n" \
  "VQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTAwMDUxMjE4NDYwMFoX\n" \
  "DTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMCSUUxEjAQBgNVBAoTCUJhbHRpbW9y\n" \
  "ZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZQmFsdGltb3JlIEN5YmVy\n" \
  "VHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKMEuyKr\n" \
  "mD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+hXe2wCQVt2yguzmKiYv60iNoS6zjr\n" \
  "IZ3AQSsBUnuId9Mcj8e6uYi1agnnc+gRQKfRzMpijS3ljwumUNKoUMMo6vWrJYeK\n" \
  "mpYcqWe4PwzV9/lSEy/CG9VwcPCPwBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSu\n" \
  "XmD+tqYF/LTdB1kC1FkYmGP1pWPgkAx9XbIGevOF6uvUA65ehD5f/xXtabz5OTZy\n" \
  "dc93Uk3zyZAsuT3lySNTPx8kmCFcB5kpvcY67Oduhjprl3RjM71oGDHweI12v/ye\n" \
  "jl0qhqdNkNwnGjkCAwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoIVDaGezq1\n" \
  "BE3wMBIGA1UdEwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3\n" \
  "DQEBBQUAA4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF+vaKSm2eT92\n" \
  "9hkTI7gQCvlYpNRhcL0EYWoSihfVCr3FvDB81ukMJY2GQE/szKN+OMY3EU/t3Wgx\n" \
  "jkzSswF07r51XgdIGn9w/xZchMB5hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/oCr0\n" \
  "Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsaY71k5h+3zvDyny67G7fyUIhz\n" \
  "ksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9HRCwBXbsdtTLS\n" \
  "R9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp\n" \
  "-----END CERTIFICATE-----\n";

uint32_t WebGet_LastTime = 0;

//***************セットアップ関数**************************
void setup() {
  Serial.begin(115200);
  delay(100);

  Serial.println();
  Serial.print("Attempting to connect to SSID: ");
  Serial.println(ssid);
  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    Serial.print(".");
    delay(500);
  }

  Serial.println();
  Serial.print("Connected to ");
  Serial.println(ssid);
  Serial.println(WiFi.localIP());
  delay(2000);

  WebGet_LastTime = 200000; //起動時に記事をGETするために、多めの数値で初期化しておく
}
//*********************メインループ***************************
void loop() {
  if((millis() - WebGet_LastTime) > 180000){ //180秒(3分)毎に記事取得
    String str = https_Web_Get("news.yahoo.co.jp", "/pickup/rss.xml", '\n', "</rss>", "<title>", "</title>", "◆ ");
    Serial.println(str);
    Serial.flush();
    WebGet_LastTime = millis();
  }
}
//*****************Yahoo RSSニュースを取得する関数*************
String https_Web_Get(const char* host1, String target_page, char char_tag, String Final_tag, String Begin_tag, String End_tag, String Paragraph){

  String ret_str;
  
  WiFiClientSecure https_client;
  https_client.setCACert(yahoo_root_ca); //Yahooサイトのルート証明書をセットする
  
  if (https_client.connect(host1, 443)){
    Serial.print(host1); Serial.print(F("-------------"));
    Serial.println(F("connected"));
    Serial.println(F("-------WEB HTTPS GET Request Send"));

    String str1 = String("GET https://") + String( host1 ) + target_page + " HTTP/1.1\r\n";
           str1 += "Host: " + String( host1 ) + "\r\n";
           str1 += "User-Agent: BuildFailureDetectorESP32\r\n";
           str1 += "Connection: close\r\n\r\n"; //closeを使うと、サーバーの応答後に切断される。最後に空行必要
           str1 += "\0";

    https_client.print(str1); //client.println にしないこと。最後に改行コードをプラスして送ってしまう為
    https_client.flush(); //client出力が終わるまで待つ
    Serial.print(str1);
    Serial.flush(); //シリアル出力が終わるまで待つ
    
  }else{
    Serial.println(F("------connection failed"));
  }

  if(https_client){
    String dummy_str;
    uint16_t from, to;
    Serial.println(F("-------WEB HTTPS Response Receive"));

    while(https_client.connected()){
      while(https_client.available()) {
        if(dummy_str.indexOf(Final_tag) == -1){          
          dummy_str = https_client.readStringUntil(char_tag);

          if(dummy_str.indexOf(Begin_tag) >= 0){
            from = dummy_str.indexOf(Begin_tag) + Begin_tag.length();
            to = dummy_str.indexOf(End_tag);
            ret_str += Paragraph;
            ret_str += dummy_str.substring(from,to);
            ret_str += "  ";
          }
        }else{
          while(https_client.available()){
            https_client.read(); //サーバーから送られてきた文字を1文字も余さず受信し切ることが大事
            //delay(1);
          }
          delay(10);
          https_client.stop(); //特に重要。コネクションが終わったら必ず stop() しておかないとヒープメモリを食い尽くしてしまう。
          delay(10);
          Serial.println(F("-------Client Stop"));

          break;
        }
        //delay(1);
      }
      //delay(1);
    }
  }
  
  ret_str += "\0";
  ret_str.replace("&amp;","&"); //XMLソースの場合、半角&が正しく表示されないので、全角に置き換える
  ret_str.replace("&#039;","\'"); //XMLソースの場合、半角アポストロフィーが正しく表示されないので置き換える
  ret_str.replace("&#39;","\'"); //XMLソースの場合、半角アポストロフィーが正しく表示されないので置き換える
  ret_str.replace("&apos;","\'"); //XMLソースの場合、半角アポストロフィーが正しく表示されないので置き換える
  ret_str.replace("&quot;","\""); //XMLソースの場合、ダブルクォーテーションが正しく表示されないので置き換える
  
  if(ret_str.length() < 20) ret_str = "※ニュース記事を取得できませんでした";
  
  if(https_client){
    delay(10);
    https_client.stop(); //特に重要。コネクションが終わったら必ず stop() しておかないとヒープメモリを食い尽くしてしまう。
    delay(10);
    Serial.println(F("-------Client Stop"));
  }
  Serial.flush(); //シリアル出力が終わるまで待つ

  return ret_str;
}

【解説】

●3-4行目:
ご自分のルーターの SSID と パスワードに書き換えてください。

●7-28行:
ここで上記で取得した Yahoo! Japan RSS ニュースサイトのルート証明書をテキストエディタで開いて、それをスケッチ上にコピペして、サンプルスケッチの書式に合わせて編集したものです。
これは、現時点ではグローバル変数領域に置いていますが、メモリを食うので、将来的には SDカードや SPIFFS に保存しておいた方が良いでしょう。

●37-50行:
ここで、Wi-Fiルーター(アクセスポイント)と接続します。

●53行:
初回起動直後に Web記事をGET するために、57行の数値より大きくしておきます。

●57-62行:
メインループで、180秒毎に Yahoo! Japan RSS ニュース記事を取得して、String 文字列に格納してシリアルモニターに表示させます。
ここの秒数は短くし過ぎないように注意してください
相手サーバーに負担をかけますし、高速で記事を連続 GET するとサイバー攻撃されていると判断されますので要注意です。

また、取得する文字列が長いので、60行目にあるように、シリアルモニターに全て出力されるまで待つ関数を使います。
Serial.flush() は昔の Arduino ではメモリをクリアする動作でしたが、今は出力が終わるまで待つという動作らしいです。

●69行目:
WiFiClientSecure ハンドルは、ここで宣言します。
ローカル関数内で宣言した方が、ローカル関数を出る時にメモリを解放してくれるので、節約につながります。

●70行目:
ここで、Yahoo! Japan RSS サイトのルート証明書をセットします。

●72行目:
ここで、Yahoo! Japan RSS サイトに SSL 通信でコネクションします。ここで、ルート証明書の照合を行っていると思われます。

●77-86行:
ここでは、Yahoo! Japan RSS サイトにニュース記事を取得するための GET リクエストを送信しています。
ここで注意することは、80行目で¥r¥nという形で空行1行を送信しているので、83行目の https_client.print を println にしないことです。
println にしてしまうと、さらに改行を送ってしまうので、レスポンスが正しく帰って来ない可能性があります。
以前、私は println にしていて、なぜか希に記事が取得できないことがありましたが、println を print に直したら、記事が100% 取得できるようになりました。
要するに、安定動作の為には、余分な文字は送らないことが大事ということです。
そして、84行目や86行目の flush は送信が終わるまで待つ関数です。
これは、効果があるのかどうかわかりませんが、気持ち的に良くなったような気がします。
注意してほしいのは、これはメモリをクリアする関数ではないということです。

●92-125行:
ここで、Yahoo! Japan RSSから送られてきたデータを受信して、必要な文字列を抽出します。
Yahooから送られてくる文字列は、ブラウザでWebページを開いた時の HTML ソースコードその物です。
そこから、ニュース記事の文字列だけを抽出します。
そして、上記でも述べたように、SSL で暗号化されて送られてくるので、それを WiFiClientSecure ライブラリで復号しているわけです。
http ページよりも多量の文字列を扱うために、メインループのスタックメモリを多く消費するので、前々回の記事で紹介したように、main.cpp のスタックサイズを増やす必要があります

詳しく調べていないのですが、おそらく、72行目の connect() 関数と、97行目の connected() 関数で公開鍵、秘密鍵のやり取りを行っていて、100行目の readStringUntil で暗号を復号しているものと思われます。

readStringUntil 関数で、改行コード(‘¥n’)まで、dummy_str に文字列を格納し、String文字列関連の関数である、indexOf 関数やsubstring関数で、<title>~</title>の間の文字列を抽出します。
ここで、注意していただきたいのは、改行コードまでの文字列取得ができるのは、対象のWebページの HTMLソースコードの各行が、比較的少ない文字数で作られていることに限ります
Webページの HTMLソースコードに、1行でも過度に長い文字列があれば、プログラムが HALT エラーを吐き出して動作停止してしまいます。
この、readStringUntil が使えるのは、1行が比較的少ない文字列で構成されている、Yahoo! Japan RSS サイトだからできるのです。

例えば、Google ニュースページや、英語のYahoo.com ページの HTMLソースコードを見てもらえれば分かるのですが、1行がもの凄く長い文字列がいくつかありますので、このプログラムは動作しません。
こういうページから記事を取得するにはプログラムを工夫する必要があります。
これについてはいつか記事にしたいと思います。

そして、最後の</rss>タグが見つかったら、110-113行で送信されてきた残りのデータを1文字も余すことなく受信し切ります
この受信を1文字でも漏らすと、あとで受信エラーになるので要注意です。
受信した文字は捨てます。

while文中でコメントアウトしてある delay(1) は、ESP32 のウォッチドッグタイマ(マイコンを監視するプログラム)が動作する余地を与えてやるため必要と思っていました。
しかし、シリアルモニターにエラーメッセージが出ないので、入れなくても良いです。
エラーが出ないということは、https_client.available() などの関数内で delayや vTaskDelay があり、ウォッチドッグタイマが起動する余地があると思われるからです。
ここでは、ESP8266 で活躍した yield() は無意味です。
Arduino – ESP32 の場合は yield() は効果が無く、delay(1) か vTaskDelay(1) だけのようです。

114行や116行では delay(10) としていますが、もっと短くても良いと思います。
ですが、今のところこれで安定動作しています。

115行目は特に重要です。
Yahoo サイトから送信されてきたデータを全て1文字も余さず受信し切ってコネクション終了したら必ず client.stop() してください
これは、GitHub の Arduino – ESP32 の issue でも述べられていますが、相手サーバーとコネクションが終わったら、client.stop() しないと、ESP32 のヒープメモリを食い尽くしてしまって、プログラムがダウンしますので要注意です。

●127-132行:
抽出した文字列の中には &amp や &#39 などという、HTML のエスケープシーケンス文字が正しく変換されていない場合があります。
その場合、String関連関数の replace を使って変換します。
ダブルクォーテーションやアポストロフィーなどの文字は、前に半角の¥文字を置いてください。

●134行:
取得した文字列があまりに少ない場合は記事を取得できていないので、その旨のメッセージを出します。

●136-141行:
ここでは、Yahooサイトとの通信が途中で途切れていたり、Yahoo側から切断された場合は、ここで client.stop() しておきます。

●142行:
シリアルモニターが時々変な表示になるので、あくまでおまじないのflush をしておきますが、あまり効果無いかも知れません。

以上、ソースコードの解説でした。

まとめると、Webページの記事取得で安定動作に大事なのは、余分な文字は送らないことと、サーバーから送られてきた文字は1文字も余すことなく受信し切ることです。
そして、所々の delay() 関数の配置と、client.stop を必ず設けることです。

そして、もう一つ大事なのは、SSLページ取得はルート証明書や公開鍵、秘密鍵の多量の文字列を扱う為、メモリを節約したプログラムを組むことです。
WiFiClientSecure ハンドルや、String 関数をローカル関数内で初期化するようにすれば、ローカル関数を出たらメモリを自動で解放してくれるので有効です。
ルート証明書は SD カードなどに保存しておく方が良いですね。

コンパイル書き込み実行

では、スケッチをコンパイルする前に、下図の様に Debug Level をVerbose ( 詳細 )に選択してからコンパイルしてください。

ESP32_WiFiClientSecure26

その後、シリアルモニターは 115200 bps で起動するとこんな感じになります。
Arduino IDE 1.8.2 以降では、このように Webから取得した文字列をそのまま シリアルモニターに日本語漢字出力ができるようになっています。

ESP32_WiFiClientSecure27

このように途中に、handle_errorメッセージがあります。

SSL – The peer notified us that the connection is going to be closed

これは、「相手サーバーからコネクション切断という通知が来た」という意味です。
つまり、サーバー 側が全てのデータを送信し切ってサーバー側から切断したことになります。
その後、こちらで client.stop() をかけて切断したので、このメッセージは特に問題有りません。

ウォッチドッグタイマが動いていないというメッセージも出ていないので、delay(1) は不要だと思います。

ある程度長い時間受信して、特に問題無ければ成功です。
これで、おそらく1000回以上連続受信も問題無くできると思います。

まとめ

以上、私なりの Arduino – ESP32 の WiFiClientSecure ライブラリを使った、Webページ記事の安定した取得方法でした。
うまく動作しましたでしょうか?

SSL通信の認証局についてはまだ勉強中なので、もし、誤っていることを言っていたらコメント投稿欄等でご連絡いただけると助かります。

mbedtls ライブラリが不具合については、早くGitHub の Arduino core for ESP32 が修正されてくれればいいんですけどね。

2017/8/2に修正されました。libmbedtls.a ファイルと main.cpp のスタックサイズも修正されました。

でも、これでブラウザの SSL 通信のしくみが少しは分かったのではないでしょうか。

ESP-WROOM-32 ( ESP32 ) が日本で発売された頃は、WiFiClientSecure ライブラリは不具合だらけで使い物になりませんでしたが、この記事で紹介した方法を使うことによって、かなり安定的に SSL ( https ) Webページをマイコンで取得することができるようになってきました。
しかも、前回記事で紹介したように、このマイコンはデュアルコア(マルチタスク)が可能なので、電子工作家としては夢のようなお話です。
ディスプレイを動かしながら裏でウェブ記事を GET することが可能なのです。

ということで、次回こそは、実際のデュアルコア電光掲示板を紹介したいと思います。

では、また・・・。

mgo-tec電子工作 関連コンテンツ ( 広告含む )

スポンサーリンク

Amazon.co.jp 当ブログのおすすめ







投稿者:

mgo-tec

Arduino , ESP32 ( ESP-WROOM-32 ) , ESP8266 ( ESP-WROOM-02 )等を使って、主にスマホと連携した電子工作やプログラミング記事を書いてます。ライブラリも作ったりしてます。趣味、独学でやってますので、動作保証はしません。 電子回路やプログラミングの専門家ではありません。 畑違いの仕事をしてます。 でも、少しだけ電気の知識が必要な仕事なので、電気工事士や工事担任者等の資格は持ってます。

コメントを残す

メールアドレスが公開されることはありません。

*画像の文字を入力してください。(スパム防止の為)