LoginSignup
2
1

More than 1 year has passed since last update.

M5Paperで日本語Webサイトの内容を表示する

Posted at

自分でやってて色々詰まったところのメモ。

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なら<!DOCTYPE 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);

できた。
IMG_0919.jpg

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1