自分でやってて色々詰まったところのメモ。
#httpsでWebサイトにアクセスする
iOSやMacだったらOSのAPIを使用すればデフォルトでインストールされているルート証明書を使ってうまいことしてくれるけれど、Arduino互換機にそういうのはないので、自分でWebサイトのルート証明書をAPIに渡さなければならない。
https://qiita.com/suin/items/59491e44f3e73a1984ff
こちらを参考にしてFireFoxで.pemファイルを取ってきた。
コードに直打ちしてもいいんだけど、後で変えたくなるかもしれないのでSDカードに入れることにした。その場合はこんな感じ。
// Load PEM file in SD card
String root_ca;
File pemFile = SD.open("/root_ca.pem");
if (pemFile)
{
root_ca = pemFile.readString();
pemFile.close();
}
// Load URL via https
String urlString = "https://somewhere/"
HTTPClient httpClient;
httpClient.begin(urlString, root_ca.c_str()));
#Chunkを結合しながらパースする
これであとはhttpClient.getStreamPtr()からstream->readStringUntil('\n')で一行ずつパースすればいいと思っていた。ところが実際にやってみたら、日本語が途中で切れたり16進数のようなものが混じったりした。ターミナルをよく見るとこういうメッセージが出ていた。
[D][HTTPClient.cpp:1264] handleHeaderResponse(): Transfer-Encoding: chunked
Transfer-Encoding: chunkedって何?これだった。
https://developer.mozilla.org/ja/docs/Web/HTTP/Headers/Transfer-Encoding
つまりレスポンスヘッダにこれが返ってきたら最初の行はサイズを表す16進数になっていて…CR+LFの次からそのサイズだけ読んだらCR+LFでぶった斬られ、またサイズを表す16進数が入り…の繰り返しになっている。ウワーッめんどくさい!でもでかいStringを作るのも嫌だしやるしかないか…
String firstLine = stream->readStringUntil('\n');
if (!firstLine.startsWith("<"))
{ // Chunk size line
useChunk = true;
chunkSize = strtol(firstLine(), NULL, 16);
}
HTTPClientってレスポンスヘッダ読めないのかな?方法が見つからなかったのでHTMLならから始まるだろうと思って、そうじゃなかったらチャンクを使用しているだろうという乱暴なことをした。まあ特定のサイトのみ見るならいいか…
ところでArduinoのStringはUTF-8が入っているので、日本語のようなマルチバイト言語では日本語で言う1文字を構成する複数のバイトの間でチャンクが切れている可能性がある。けど、UTF-8の2バイト目から始まっているStringがあったところで別にそこはチェックされないらしいので、そのまま繋げてしまえば大丈夫だった。
#日本語フォントを読み込む
こちらを参考にさせていただいたけど、フォントは普通にSDカードに置いた。
https://neocat.hatenablog.com/entry/2021/04/10/073043
M5EPD_Canvas canvas(&M5.EPD);
// load font
canvas.loadFont("/font.ttf", SD);
canvas.createRender(36, 256);
canvas.setTextSize(36);
フォントはIPAフォントとか…M+フォントとかが使いやすそう。
https://moji.or.jp/ipafont/
https://mplus-fonts.osdn.jp
#行の折り返しとかを計算する
Canvasに文字列を折り返しながら描画すると高さがどうなるか返す関数とか無いのかなと思ったら無かった。
https://docs.m5stack.com/en/api/m5paper/epd_canvas
文字列の幅を返す関数ならあるように見えるじゃんか。これ、TTFフォントを読み込ませた状態だと0を返すらしい。
int16_t textWidth(const String& string)
じゃあ等幅フォントを使って(英数字部分は過大に計算されるとしても)文字数から幅を計算して…それを指定の幅で折り返すと何行になるという計算をするしかないか…でも思い出してほしい。StringはUTF-8なので、length()はバイト数しか返ってこない。
結局こちらを参考にして、日本語の文字数を計算するコードを書いた。サロゲートペアはどうなんのかな
https://yama-3.net/c/str-count3
#指定エリアに描画する
まあ書いてあるけど、setTextWrapで折り返しをオンにして、setTextAreaでさっき計算した高さとかを指定して、printすればいいらしい(drawStringではない)。折り返しにxとyがあるんだけどxはfalseでもいいのかな…
https://docs.m5stack.com/en/api/m5paper/epd_canvas
canvas.setTextWrap(true, true);
canvas.setTextArea(x, y, width, height);
canvas.println(text);