Orange Pi Zero2のケースをシール容器で作ってみた

Orange Pi Zero2を購入したのだが、これは今のところ専用ケースの販売が無い。基板むき出しでも使えはするが、やはり何かしらのケースが無いと置き場所に困るしホコリまみれも良くない。そこで、ケースを作ることに。以前はAliExpressなどでアルミエンクロージャを購入して穴あけをしていたが、近頃はアルミケースの類は送料が地味に高くて買う気になりにくい。今回は、できるだけ安くということで100円ショップで販売されているプラスチックのシール容器(俗に呼ばれるタッパー)。4個セットで100円(税込み110円)なので1つなら25円(27.5円)。安くて良いね。見た目は悪いけど。

Orange Pi Zero2のケースを作る 1
今回利用するのは写真のシール容器。4個セットだけど2つは既にネジ入れなどに使用済み。ラベルに書かれているサイズがw85 x d66 x h31mmとなっているが、これでOrange Pi Zero2のケースとしては縦は1mmの余裕もなく、横は頑張れば1mmほどズラすことができる程度。なんか、Orange Pi Zero2を入れるために作られたのではないかというほどぴったりサイズ。

Orange Pi Zero2のケースを作る 2
USBのType-AとType-C、LANポートの位置にテキトーに印を付けて、そこにドリルでこれまたテキトーに穴を開ける。他に、microSDカードのスロットとアンテナ端子、ヒートシンクに排熱するための銅ブロックの穴も開ける。

Orange Pi Zero2のケースを作る 3
ドリルで穴を開けた後は、彫刻刀の「小刀」を使う。これ以外は要らない。刃が毀れると良くないので彫刻刀はあまり研がない方が良いかも。カッターナイフは危ないので使わない。先にドリルで穴を開けると書いたが、小刀なら力を入れればシール容器のプラスチックくらいは貫通できる。ただし、この手のシール容器は一点に力が集中すると簡単にバッキリ割れるので小刀で貫通させるようなことはしない方が間違いがない。また、ドリルで開けた穴から、いきなり目的のサイズに穴を拡げるのではなく、0.5mm〜1.5mmずつ薄く削り取るように穴を拡げてゆくと力も要らずサクサク削りやすい。

Orange Pi Zero2のケースを作る 4
これは背面側、印どおりに穴を開けたのだが、そもそも印の付け間違い。シール容器のフタに近い側の「でっぱり」の高さに基板がくる予定で作るつもりだが、それなら写真の向きであればmicroSDカードは基板の上側なのに穴を開ける側を間違えていた。まぁ、穴を開けてしまったものは仕方がないので正しい位置にもう1つ穴を開けることにする。また、アンテナ端子用の穴も開ける。これはピンヘッダ等の邪魔にならなければ何処でも良いかと。

Orange Pi Zero2のケースを作る 5
正面の各種端子が並ぶ側にも穴を開けた。micro HDMI端子は使う予定がないので穴は無し。USB Type-Cだけはケーブルのプラグとシール容器の「でっぱり」が干渉するのでそこだけ「でっぱり」を削り取る。

Orange Pi Zero2のケースを作る 6
Orange Pi Zero2には最初からWi-Fiアンテナが接続済みだが、Orange Pi Zero2技適は取得していないのでこれは当然日本では使用NG。そこでIPXとSMAの変換ケーブルにつなぎ替える。

Orange Pi Zero2のケースを作る 7
Orange Pi Zero2のSoCであるH616は正方形ではなく長方形だが、15 x 15mmの銅パッドで問題なさそう。それを熱伝導テープでSoCの上面に貼り付ける。銅である必要はないが、なにかしらの熱伝導パッドが無いと周囲のチップ等と干渉するので次の銅ブロックを載せられない。

Orange Pi Zero2のケースを作る 8
銅パッドに上にさらに銅ブロックを乗せるので銅パッドの上に熱伝導テープを貼り付ける。最終的には上の写真のようにする予定だが、シール容器に納めていない状態で、デタラメに銅ブロックを乗せるとシール容器と干渉する可能性があるので、シール容器に基板を入れてから最後に銅ブロックを嵌める。シール容器に基板を納めるときは熱伝導テープに触れないよう慎重に。

Orange Pi Zero2のケースを作る 9
microSDカード用のスロットを正しい位置に開け直した。上の写真ではmicroSDカードが飛び出ているが、正しい位置にセットするとシール容器と面が合う程度なのでシール容器のフタを閉める邪魔にはならない。
また、アンテナ端子もシール容器に取り付けた。

Orange Pi Zero2のケースを作る 10
銅ブロックをシール容器の穴に沈め、上から軽く抑えて暫く放置すれば、熱伝導テープでガッチリ固定される。
アンテナ端子にはもちろん電波が出ないようダミーロードを取り付けた。

Orange Pi Zero2のケースを作る 11
上にテキトーに選んだヒートシンクを載せた。もちろん、銅ブロックとヒートシンクは熱伝導テープでがっちり固定済み。
正面側はこんな感じになった。すでに書いたようにUSB Type-AとType-Cの中間にあるmicroHDMI端子は使わないのでシール容器の穴が無い。

Orange Pi Zero2のケースを作る 12
USB Type-Cのケーブルをつないでみた。シール容器のでっぱりを削ったので問題なく接続できる。

Orange Pi Zero2のケースを作る 13
基板四隅にM3のネジを取り付け、シール容器のフタを閉めた状態で基板の高さが合うようにネジの飛び出る長さを調整する。このとき、microSDカードとUSB Type-Cのケーブルを接続した状態で行うと上手くいくかと。なお、microSDカードに無理な力が加わらないよう注意。

削りやすい素材で、サクサク削れたので作業時間は全部で30分程度。誰でもできる簡単な作業なのでオススメかも。見た目が残念だけど。

Orange Pi Zero2を触ってみた

Orange Pi Zero2

Allwinner H5を搭載したOrange Pi Zero Plus (以下OPi0+)が突然死したらしく、電源のオフ・オンを行ってもらってもLEDが点かないということで(自身では実物を見てないので本当のところは不明)、急遽新しいSBCを購入することに。で、一番カンタンなのはおそらく全く同じOPi0+を購入すること。microSDカードを壊れたらしいOPi0+から新しいOPi0+に差し替える、またはバックアップイメージを新しいmicroSDカードに焼いて新しいOPi0+に挿す。これだけでイケる筈。
しかし、Allwinner H5は生産中止(いわゆるディスコン)という話で、H5を搭載したSBCはOrange Piだけでなく他社製品含め軒並み在庫切れ。
どうするか、で目を付けたのが2020年11月発表12月販売開始したばかりのOrange Pi Zero2 (以下OPi02)。OPi02はAllwinnerのSoCだけどH5でもH6でもなくTV Box・メディアプレーヤー向けというH616という詳細不明なSoCを搭載したSBC。4コアなCortex-A53らしい。OPi02はmicroタイプだけどHDMI端子が付いてるので自身でメディアプレーヤーを作るというのもアリなのかな。メモリは512MBと1GBの2種類から選べる。メディアプレーヤーだとちょっと少ないかも。USBはType-AとType-Cが1つずつ。ネットワークは有線がRTL8211Fで10/100/1000Mpbs、無線がAW859AでIEEE 802.11 a/b/g/n/ac対応、Bluetoothはv5.0対応となっている。
電源はType-CのUSBポートを使う。5V/2Aなので「がとらぼ」ではよく登場するダイソーのUSB ACアダプタでも問題なく動く。
基板サイズは60 x 53mm、重量は30gということになっている。(Orange Piの公式サイトの情報)
性能はH5と比べて大きく劣ることはないだろうし、なにしろ安い。1GBのメモリを搭載したタイプで実売価格は約2千円。送料が別途500円ほど。つまり、メモリが512MBのOPi0+より$5高いけどメモリを512MB増量したと考えると同価格くらいかな?しかもHDMI出力有りと考えるとお買い得。

Orange Pi Zero2 1
注文したのが2020年12月24日で、到着が2021年1月4日。運送便は名目がAliExpress Standard Shippingで実際のロジはYanwen。Yanwenといえばこれまで早くて3週間程度という認識だったが初めての10日ちょうど。(発送は注文日の翌日午後で到着は午前中なので) 中華郵政で10日というのは昔はちょくちょくあったけどYanwenでこんなにすぐ届くって狐につままれたみたい。
上の写真では後から貼られた伝票の紙の貼り方が汚いので見た目が悪いけど中がスカスカな割にダンボールは潰れてない。

Orange Pi Zero2 2
ダンボール箱の中に入っていたのは右の白い箱1つ。緩衝材無し。左は大きさ比較用のmicroSDカード(のパッケージ)。
写真だと大きさが伝わらないかと思うけどキャッシュカードより一回り大きい程度なので実物はかなり小さい印象。

Orange Pi Zero2 3
箱の中身。OPi02と紙ペラ1枚だけ。OPi02を入れた静電気防止袋は融着で密封されていた。

Orange Pi Zero2 4
OPi02の基板。左にあるのはSDカード(のアダプタ)。OPi0+よりは少しだけ大きいとはいえ、60 x 53mmなので小さいよね。左にニョロンと伸びているのはWi-Fiのアンテナで、届いた時点で接続済み。アンテナ接続部分はIPX端子になっているのでもちろん取り外し可能。というか、OPi02は技適が無い製品なのでOPi02を日本で使うならアンテナを外してダミーロードを取り付ける。

Orange Pi Zero2 5
基板のオモテ側。中央のH616と書いてあるチップがSoC。H616の左に見える蟹が逆さまになったチップが有線LANのNIC。左下に見えるAW859Aと書いてあるチップがWi-FiとBluetooth。H616の上に見えるAXP305が電源管理ユニット(PMU)。H616の右側に2つあるSEC 031 K4B4G16 46E BYMAはSumsungのDDR3メモリで1つが512MB、この基板には2枚付いているので1GBになる。

Orange Pi Zero2 6
基板のウラ側。右下の方にあるmicroSDカードのスロットとその左のSPI Flashのチップ以外に大きな部品は無い。microSDカードスロットはバネ式。奥まで差し込むと少し戻ってロック、もう1度押し込むとリリースされるタイプ。この面にはシールが貼られていて、20201210で始まる数字は製造日?

Orange Pi Zero2 7
端子類のある側。左からUSB2.0 Type-A, Micro-HDMI 2.0a, USB Type-C(電源用)、RJ45 10/100/1000Mbps。
右端に見えている13ピンのGPIOはUSB2.0 x2とオーディオ出力他。左端に見えている26ピンのGPIOはI2C, SPI, UARTということらしい。使う気が無いので未確認。

いつもarmbianを使っているのでOPi02でもarmbianを使おうと思ったのだが、armbianのウェブサイトには12月中旬という古めのDebian BusterとFocalのイメージと1月3日付けのUbuntu Groovyのかなり怪しそうなのしか置いてなかった。1月4日に配達になるとは予想してなかったのでarmbianの最新のソースから大慌ててビルドしたが、ビルド自体は成功したものの、OPi02に挿したところ、動作しないみたい。有線LANの緑とオレンジのLEDが点灯状態で基板上のLEDが光らない状態。それ以外はそもそも動いているのかどうかも不明という状態。microタイプのHDMIに対応したケーブルを持ってないので画面で確認できない。ネットワーク側をarpで確認すると不完全な情報だけが得られる(つまりネットワーク的には使えない)状態。いろいろ試したがどうもダメだと判明するまで数時間ムダにした。armbianのサイトに置いてある古いのは動くかもしれないけど、それも確実とはいえないかもなのでOrangePiのサイトから2020年11月4日付けというこれまた古そうなDebianのイメージファイルをダウンロードして焼いた。
これは流石にサクッと動いた。

Orange Pi Zero2 8
これは動かし始めてから半日過ぎてからのSSHログイン直後の画面。室温の低い中、大きなヒートシンクを付けてしっかり冷却できている環境で長時間アイドル状態だが、SoCの温度計では37℃になっている。夏場大丈夫なのかしら?

UnixBench

========================================================================
   BYTE UNIX Benchmarks (Version 5.1.3)

   System: orangepizero2: GNU/Linux
   OS: GNU/Linux -- 4.9.170-sun50iw9 -- #25 SMP PREEMPT Fri Dec 4 12:46:25 CST 2020
   Machine: aarch64 (unknown)
   Language: en_US.utf8 (charmap="UTF-8", collate="UTF-8")
   21:28:08 up 11 min,  1 user,  load average: 1.10, 1.03, 0.65; runlevel unknown

------------------------------------------------------------------------
Benchmark Run: Mon Jan 04 2021 21:28:08 - 21:56:05
0 CPUs in system; running 1 parallel copy of tests

Dhrystone 2 using register variables        7575270.8 lps   (10.0 s, 7 samples)
Double-Precision Whetstone                     1765.0 MWIPS (9.8 s, 7 samples)
Execl Throughput                                829.5 lps   (30.0 s, 2 samples)
File Copy 1024 bufsize 2000 maxblocks        140195.6 KBps  (30.0 s, 2 samples)
File Copy 256 bufsize 500 maxblocks           41796.4 KBps  (30.0 s, 2 samples)
File Copy 4096 bufsize 8000 maxblocks        374112.6 KBps  (30.0 s, 2 samples)
Pipe Throughput                              262601.6 lps   (10.0 s, 7 samples)
Pipe-based Context Switching                  48098.9 lps   (10.0 s, 7 samples)
Process Creation                               1995.0 lps   (30.0 s, 2 samples)
Shell Scripts (1 concurrent)                   2262.4 lpm   (60.0 s, 2 samples)
Shell Scripts (8 concurrent)                    589.5 lpm   (60.1 s, 2 samples)
System Call Overhead                         427956.2 lps   (10.0 s, 7 samples)

System Benchmarks Index Values               BASELINE       RESULT    INDEX
Dhrystone 2 using register variables         116700.0    7575270.8    649.1
Double-Precision Whetstone                       55.0       1765.0    320.9
Execl Throughput                                 43.0        829.5    192.9
File Copy 1024 bufsize 2000 maxblocks          3960.0     140195.6    354.0
File Copy 256 bufsize 500 maxblocks            1655.0      41796.4    252.5
File Copy 4096 bufsize 8000 maxblocks          5800.0     374112.6    645.0
Pipe Throughput                               12440.0     262601.6    211.1
Pipe-based Context Switching                   4000.0      48098.9    120.2
Process Creation                                126.0       1995.0    158.3
Shell Scripts (1 concurrent)                     42.4       2262.4    533.6
Shell Scripts (8 concurrent)                      6.0        589.5    982.5
System Call Overhead                          15000.0     427956.2    285.3
                                                                   ========
System Benchmarks Index Score                                         325.1

------------------------------------------------------------------------
Benchmark Run: Mon Jan 04 2021 21:56:05 - 22:24:05
0 CPUs in system; running 4 parallel copies of tests

Dhrystone 2 using register variables       30327186.0 lps   (10.0 s, 7 samples)
Double-Precision Whetstone                     7057.8 MWIPS (9.8 s, 7 samples)
Execl Throughput                               2410.4 lps   (29.9 s, 2 samples)
File Copy 1024 bufsize 2000 maxblocks        239580.5 KBps  (30.0 s, 2 samples)
File Copy 256 bufsize 500 maxblocks           64481.1 KBps  (30.0 s, 2 samples)
File Copy 4096 bufsize 8000 maxblocks        696793.9 KBps  (30.0 s, 2 samples)
Pipe Throughput                             1046088.6 lps   (10.0 s, 7 samples)
Pipe-based Context Switching                 168832.4 lps   (10.0 s, 7 samples)
Process Creation                               4365.5 lps   (30.0 s, 2 samples)
Shell Scripts (1 concurrent)                   4595.3 lpm   (60.0 s, 2 samples)
Shell Scripts (8 concurrent)                    622.6 lpm   (60.2 s, 2 samples)
System Call Overhead                        1675554.8 lps   (10.0 s, 7 samples)

System Benchmarks Index Values               BASELINE       RESULT    INDEX
Dhrystone 2 using register variables         116700.0   30327186.0   2598.7
Double-Precision Whetstone                       55.0       7057.8   1283.2
Execl Throughput                                 43.0       2410.4    560.6
File Copy 1024 bufsize 2000 maxblocks          3960.0     239580.5    605.0
File Copy 256 bufsize 500 maxblocks            1655.0      64481.1    389.6
File Copy 4096 bufsize 8000 maxblocks          5800.0     696793.9   1201.4
Pipe Throughput                               12440.0    1046088.6    840.9
Pipe-based Context Switching                   4000.0     168832.4    422.1
Process Creation                                126.0       4365.5    346.5
Shell Scripts (1 concurrent)                     42.4       4595.3   1083.8
Shell Scripts (8 concurrent)                      6.0        622.6   1037.6
System Call Overhead                          15000.0    1675554.8   1117.0
                                                                   ========
System Benchmarks Index Score                                         811.7

過去に測定したSBCに載っていたH5と同じくH616はクアッドコア。今回もUnixBenchは、1パラレル(シングル)と4パラレルで測定。
インデックススコアはシングルが325.1、4パラレルが811.7。
H5を搭載したNanoPi NEO2をFriendlyELECが提供するUbuntuで測定したときの結果とインデックススコアで比較すると、シングルで僅かに勝り、4パラレルで僅かに負ける。ただし、誤差程度。
NanoPi NEO2とOPi02は価格が大して変わらないこともあり性能が同程度でも仕方ないところではあるかもしれないが、しかし、4年ちかくも前の製品と性能が変わらないというのはちょっと残念かも。OPi02にはHDMI出力とWi-Fi, Bluetoothが付いてるけどね。

ウェブのYouTube動画埋め込みは遅延読み込みで

WordPressには、記事の作成エディタで1行の中にYoutubeの動画URLだけを書くと(ページ表示には)自動的にYoutube動画の再生画面にしてくれる便利な機能(oEmbed)がある。
コンテンツを作る側としてはメッチャ簡単なので嬉しいのだけど、これがページ表示の速さという面では非常によろしくない。ページ表示が遅いということは第一に閲覧者にとって良くない。そして、本来はオマケではあるが、Googleさんの評価が悪いのでそれはすなわちコンテンツを提供する側(記事を作る側)にも良くない。

WordPressの記事中にYoutubeの動画URLを書く。
https://www.youtube.com/watch?v=動画ID (同じ行に動画URL以外の文字を書くとおそらくNG)

これはページ表示時には以下のように展開され、Youtubeの動画プレーヤーが表示される。
<iframe title="動画タイトル" width="624" height="351" src="https://www.youtube.com/embed/動画ID?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

見れば判るがiframeの動画埋め込み形式になっている。これを普通に表示させようとするととても遅い。

Youtubeプレーヤー
こんなのが表示される。なお、上はただの画像なのでクリックしても何も起きない。

iframeタグのlazyload 1
このiframeのYouTube動画を埋め込んだページをGoogleのPageSpeed Insightsで採点してもらうと42点という驚きの低評価。「診断」の項目で「第三者コードの影響を抑えてください」という項目があるので展開すると、YouTubeのJavascriptがページ表示を邪魔していることが判る。YoutubeのCSSは、それ自体がページ表示の邪魔をしている時間はゼロということになっている。影響しているのは YouTubeの base.js と www-embed-player.js。

対策方法をググると、数行のJavascriptを書いてiframeタグのsrc="Youtubeの動画URL"をsrc=""に変更し、data-set="Youtubeの動画URL"を追加するという記事が多くヒットする。
でも、このやり方は他にLazy load系のスクリプトを使っているとコンフリクトする可能性があるし、何より2020年夏よりiframeの遅延読み込み(lazy-load)対応がウェブ標準になっている(Chromeなどの一部ブラウザでは2019年夏から)ので無駄な感じ。
シンプルにiframeタグ内に loading="lazy" を書くだけ。これで古いブラウザで表示する場合以外は問題無いしWordPress側を改造したりプラグインを加えて汚す必要もない、そして簡単。

ただし、WordPressでYoutube等の動画をURL1行記述にしていたらそれをiframe手書きに書き換えなきゃならないけど。

<iframe loading="lazy" width="854" height="480" src="https://www.youtube.com/embed/Q2zcPxCn3vg" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
黄色の文字列を追加するだけ。

それか、YouTubeの動画リンクの展開用のoEmbedの関数をオーバーライドするとか。 記事の最後に追記しました

iframeタグのlazyload 2
このページのYoutube動画の埋め込みは元から1つだけ。
そして、YouTubeの動画をURL1行書きからiframeタグのLazy Loadありに変えただけ。他は全く弄っていない。それだけで、42点から50点加点されて92点になる。というか、これまで無駄に50点減点されていた。いきなり点数が倍以上なのは笑う。
ちなみに、少し前までであればこれで100点になるのだが、最近は画像サイズと特にTTFBの判定が辛めになっているので100点にはならないことが多いかと。TTFBは、Googleさんは日本からの計測ではないようなのでCDNを利用していない日本だけにサーバがあるウェブサイトはちょっとキビシイ判定になる筈。この「がとらぼ」をKeycdnのPerformance Testで計測すると東京(Tokyo)での判定は120ms程度なのでサーバーが非力とはいえGoogleさんに指摘される程は悪くない筈なのよね。

この記事ではWordPressでYoutubeの動画URL1行記述を例に挙げたけど、YouTubeで表示される埋め込みコードを使う場合も同じこと。iframeタグにloading="lazy"を追加しましょう。
あと、YouTubeだけでなく、iframeは多くの場面で遅延読み込みで良いと思う。iframeがファーストビューの範囲にあると効かないと思うけど。

記事公開数時間後に追記

過去記事のYouTubeのURL1行記述と、手書きのiframeを探して loading="lazy" を追加しようとしたら、少ない筈と思っていたのが意外と多かった。そして「面倒だな」と思う気持ちが強くなってしまったのでYouTubeのURL1行記述の方はWordPressのfilterでオーバーライドする方が簡単そうに思った。

oEmbedについてはwp-includes/class-wp-oembed.phpを見た。
WordPressのoEmbedで対応する動画サイトやSNS等のURLもこのファイルに書かれてる。
m.youtube.com, www.youtube.com, youtu.be, *.vimeo.com, www.dailymotion.com, www.flicker.com, flic.kr, www.twitter.com, amazonいろいろなど、これはほんの一部で結構多く対応しているみたい。

で、oEmbedのタグにYouTubeのドメイン名(youtube.com, youtu.be)が含まれていたらiframeタグにloading="lazy"を追加するフィルタを作ってみた。

下のコードはWordPressで使用中のテーマのfunctions.phpの中に追加する。(wp-content/themes/使用中テーマ/functions.php)

1
2
3
4
5
6
7
function oEmbed_youtube_lazyload($tag){
  if(strpos($tag, 'youtube.com') !== false || strpos($tag, 'youtube.be') !== false){
    $tag = preg_replace('/iframe /', 'iframe loading="lazy" ', $tag);
  }
  return $tag;
}
add_filter('embed_oembed_html', 'oEmbed_youtube_lazyload');

もしくは、YouTubeだけでなく、とにかくoEmbedでiframeタグだったらloading="lazy"を追加するフィルタを作ってみた。YouTube以外でiframeが使われているのかを含めてこちらは動作未確認。そして、上のYoutube用フィルタとは同時に使わないでどちらか1つだけ。

1
2
3
4
5
6
7
function oEmbed_iframe_lazyload($tag){
  if(strpos($tag, 'iframe') !== false){
    $tag = preg_replace('/iframe /', 'iframe loading="lazy" ', $tag);
  }
  return $tag;
}
add_filter('embed_oembed_html', 'oEmbed_iframe_lazyload');