はじめに
RaspberryPi5で、OLEDディスプレイを使う方法について解説します。
言語は「Python(CPython)」、ライブラリは「adafruit-circuitpython-ssd1306」を使用します。
実は今回使う「adafruit-circuitpython-ssd1306」は、RaspberryPi Picoなど、CircuitPythonで動くマイコン用のライブラリで、そのままではノーマルのRaspberryPiの「Python(CPython)」では使えません。
ですが、同じくAdafruit製の「Blinka」というライブラリ(ミドルウェア)を使えば、ノーマルのRaspberryPiからCircuitPython用のライブラリが使えるようになります。
このBlinkaの仕組みが結構おもしろかったので、今回は「Brinka」と「CircuitPython用のライブラリ」を使って、OLEDに表示RaspberryPiのIPアドレスを表示してみたいと思います。
Brinka(ブリンカ)
アメリカのAdafruit Industries社が開発した、CPythonからCircuitPython(Micro Python)を動かすための、特殊なライブラリ(ミドルウェア)です。
「トランスパイラ」というツールを備えており、CircuitPythonのコードを普通のPython(CPython)コードに変換することができます。
上記の返還をかけることで、普通のPythonしか使えないノーマルのRaspbrryPiや、Jetsonのようなシングルボードコンピュータ(SBC)でも、CircuitPythonを動かすことができます。
ちなみに「RaspberryPiにCircitPythonをインストールしちゃえば?」と思われるかもしれませんが、CircuitPythonは、OSがないマイコンで使われることを前提にした環境です。
そのため、「RaspberryPiのOS」と「CircuitPython」は同居することはできず、Brinkaのようなミドルウェアが必要になります。
なぜIPアドレスを表示?
RaspberryPiを無線LANでのログインで使っていると、IPアドレスを忘れたり、IPが変わってしまってログインできなくなることがありますよね。
固定IP設定や、設定したIPのメモを作ればいいのですが、ディスプレイ上でIPアドレスを表示がでるようにしておけば、固定IPやメモも不要になります。
ということで、今回ディスプレイにIPアドレスを表示することにしてみました。
~ この記事の内容 / Contents ~
環境
この記事で使用する環境は以下の通りです。
環境 | 内容 | 備考 |
OS | RaspberryPi OS | bookworm |
言語 | Python | Ver.3.11.2 |
ライブラリ | adafruit-circuitpython-ssd1306 | Ver.2.12.17 |
adafruit-circuitpython-framebuf | Ver.1.6.5 | |
ミドルウェア | Adafruit-blinka | Ver.8.85.0 |
ボード | RaspberryPi 5 |
RaspberryPi 5とOLEDディスプレイの接続
RaspberryPi 5とOLEDディスプレイを以下のように接続します。
ピンアサイン
※ RaspberryPi 公式のGitHubより引用
使用する部品
RaspberryPi5
RaspberryPi 5技適も取得されて、国内販売品もだいぶ出回るようになりました。マイクロSDも忘れずに用意してください。
RaspberryPi 5 電源
RaspberryP 5は、5v5Aという特殊な仕様の電源アダプタが必要です。公式は少し高いので私はPSEマーク付きのこちらのものを使っています。
OLEDディスプレイ
I2C接続のOLEDディスプレイです。SSD1306チップを搭載しています。
OLEDディスプレイ(HATタイプ)
少し高くなりますが、HATタイプもあります。Amazonがなぜかすごく高いので、代わりのショップ(2500円~3000円程)も載せておきます。
ブレッドボード(ハーフサイズ)
サンハヤト製のブレッドボードです。今回は簡単な回路なので小さいサイズのものを使っています。
ジャンパワイヤ(オス-メスタイプ)
RaspberryPiとブレッドボードで使うなら、以下のオス-メスタイプを使います。
プログラム概要
今回のプログラムの概要は以下の通りです。
- IPアドレスを取得する
- OLEDにIPアドレスを表示する
「CircuitPython」と「Blinka」のインストール
以下のコマンドてCircuitPython・Blinka、IPを簡単に取得するためのライブラリ「Ipget」をインストールします。
CircuitPython、Blinkaのセットアップ方法については、公式の以下のページをベースにしています。
パッケージ管理ソフトを更新する
以下のコマンドで、まずはapt-getなどのパッケージ管理ソフトを最新にします。
sudo apt-get update
sudo apt-get -y upgrade
sudo apt-get install python3-pip
sudo apt install --upgrade python3-setuptools
Python仮想環境の構築
アップデートが完了したら、以下のコマンドでPythonの仮想環境を構築します。
cd ~/
python3 -m venv env --system-site-packages
構築完了後、以下のコマンドで仮想環境を有効化してください。
source ~/env/bin/activate
コマンドの実行後、以下のように「(env)」と表示されれば有効化は完了です。そのままの状態でライブラリのインストールに進んでください。
esu@raspberrypi:~ $ source ~/env/bin/activate
(env) esu@raspberrypi:~ $
前述の仮想環境の有効化後に端末を閉じてしまったり、中断してライブラリのインストールを再開した時は、再度以下のコマンドを実行してから、インストールを再開してください。
source ~/env/bin/activate
仮想環境を終了したい時は、以下の「deactivate」コマンドで終了できます。
(env) esu@raspberrypi:~ $ deactivate
esu@raspberrypi:~ $
Blinkaのインストール
以下のコマンドで、Blinkaをインストールします(数分かかります)。
cd ~
pip3 install --upgrade adafruit-python-shell
wget https://raw.githubusercontent.com/adafruit/Raspberry-Pi-Installer-Scripts/master/raspi-blinka.py
sudo -E env PATH=$PATH python3 raspi-blinka.py
最後のほうで、以下のように再起動の確認が表示されるので「Y」を入力します。
Settings take effect on next boot.
REBOOT NOW? [Y/n] Y
RaspberryPiが自動的に再起動する(再起動完了後のメッセージなどはありません)ので、際ログイン後または、端末から以下のコマンド実行します。
ls /dev/i2c* /dev/spi*
下のように表示されたら、Blinkaのインストールは完了です。
/dev/i2c-1 /dev/i2c-11 /dev/i2c-12 /dev/spidev0.0 /dev/spidev0.1 /dev/spidev10.0
ライブラリのインストール
OLEDに必要なライブラリをインストールします。Pythonの仮想環境を有効化した状態で作業してください。
CircuitPython-ssd1306のインストール
以下のコマンドで「adafruit-circuitpython-ssd1306」をインストールします。
source ~/env/bin/activate
pip3 install adafruit-circuitpython-ssd1306
adafruit-circuitpython-framebufのインストール
OLEDで文字表示を行う際に必要な「adafruit-circuitpython-framebuf」をインストールします。
pip3 install adafruit-circuitpython-framebuf
フォントファイルのインストール
以下の場所から、文字表示用のフォントファイルをダウンロードします。
下記のリンク先のダウンロードボタンからファイルをダウンロードし、後述するプログラムと同じ場所に保存してください。
右クリック・保存などでダウンロードすると、コードを実行する際にエラーになることがあります。必ず上記ページのダウンロードボタン(下矢印(↓)のボタン)でダウンロードしてください。
ipgetのインストール
以下のコマンドで「ipget」をインストールします。ipgetがインストールできたらライブラリのインストールは完了です。
pip3 install ipget
実行結果
後述するコードを実行すると、以下のようにOLEDディスプレイにRaspberryPi5のIPアドレスが表示されます。
全体コード
全体コードは以下の通りです。詳細な内容は後述する「コードのポイント」で解説します。
# CircuitPythonの各モジュールをインポートします
from board import SCL, SDA
import busio
# CircuitPython-ssd1306ライブラリをインポートします
import adafruit_ssd1306
# ipgetをインポートします
import ipget
# i2c通信用のオブジェクトを生成します
i2c = busio.I2C(SCL, SDA)
# OLEDディスプレイ用のオブジェクトを生成します
# 引数は横のピクセル数、縦のピクセル数、I2C通信用のオブジェクトです
display = adafruit_ssd1306.SSD1306_I2C(128, 64, i2c)
# ディスプレイの表示内容を初期化します
display.fill(0)
display.show()
# ipget用のオブジェクト生成します
ip = ipget.ipget()
# 無線LANのIPアドレスを取得します
ip_str = ip.ipaddr("wlan0")
# お使いの環境に合わせて修正してください。
font_path = "/home/esu/src_python/font5x8.bin"
# 取得したIPアドレスの表示を準備します
display.text("My IP Addr is", 0, 10 ,1,font_name=font_path)
display.text(ip_str, 0, 20 ,1, font_name=font_path)
# 準備した内容を表示します
display.show()
プログラムの実行方法
Pythonの仮想環境を有効化して、以下のコマンドを実行します。
source ~/env/bin/activate
python3 pi_circuitpython_ssd1306.py
コードのポイント
SSD1306オブジェクトの作成
OLEDディスプレイ用のオブジェクトを生成します。
引数には、ディスプレイの縦横のピクセル数とi2c通信用のオブジェクトを渡します。
# OLEDディスプレイ用のオブジェクトを生成します
# 引数は横のピクセル数、縦のピクセル数、I2C通信用のオブジェクトです
display = adafruit_ssd1306.SSD1306_I2C(128, 64, i2c)
OLEDディスプレイの初期化
ディスプレイの表示内容を初期化(クリアします)。
ディスプレイの表示は「追記」の形式で行われるため、初期化せずに描画を行ってしまうと、前回の表示内容と、今回の表示内容が混ざってしまいます。
そのため、全体を埋めるfill関数に0(黒)を渡して、ディスプレイのクリアを行います。
# ディスプレイの表示内容を初期化します
display.fill(0)
display.show()
IPアドレスの取得と表示
取得するネットワークの名前を指定して、IPアドレスを取得します。
ネットワーク名は「ifconfig」のコマンドなどで確認できますが、基本的に無線LANを使う場合は「wlan0」と指定すれば問題ないはずです。
# 無線LANのIPアドレスを取得します
ip_str = ip.ipaddr("wlan0")
text関数とフォントファイルの指定
文字列の表示は、text関数で文字列(英数字・記号)、表示する場所のX座標(横位置 )Y座標(縦の位置)をピクセルで指定します。
プログラム単体を手動実行する場合、フォントファイルの場所を省略しても、プログラムと同じ場所を参照してくれます。
しかし、後述する自動起動の場合は、カレントは参照されず、ライブラリ内部でエラーが発生してしまうため、フォントファイルの絶対パスでの指定が必要です。
フォントファイルの絶対パスは、お使いの環境に合わせて変更してください。
# お使いの環境に合わせて修正してください。
font_path = "/home/esu/src_python/font5x8.bin"
# 取得したIPアドレスの表示を準備します
display.text("My IP Addr is", 0, 10 ,1,font_name=font_path)
display.text(ip_str, 0, 20 ,1, font_name=font_path)
起動時に自動でPythonプログラムを起動する
プログラムが作成できたら、RaspberryPiの起動時にIPを確認できるように、自動実行の設定を行います。
シェルスクリプトの作成
Python仮想環境下でプログラムを実行する、下記のシェルスクリプトを作成します。
※ ディレクトリ名などは、お使いの環境に合わせて変更してください。
#!/bin/sh
/home/esu/env/bin/python3 /home/esu/src_python/circuit-python_ssd1306.py
実行権限の付与
シェルスクリプトが作成できたら、以下のコマンドで実行権限を付与します。
chmod 775 oled_ip.sh
systemd用サービスの作成
RaspberryPi OSでは、デフォルトでsystemdというシステムを使って起動時に実行するプログラムを管理しています。systemdが実行するプログラムは「サービス」と呼ばれ、下記の内容を作成、登録することで、systemdが処理を実行してくれるようになります。
今回のIP表示では、以下の「oled_ip.service」を作成します。
※ ディレクトリ名はお使いの環境に合わせて適宜変更してください。
[Unit]
# この設定の説明です
Description=Display IP on oled.
# いつ実行するかを指定します(ネットワーク確立後の指定)
After=network-online.target
[Service]
# サービスの種類です。
Type=oneshot
# 実行したプログラムが終了しても、サービスをアクティブと見なすか
RemainAfterExit=yes
# 実行するコマンド
ExecStart=/home/esu/src_python/oled_ip.sh
[Install]
WantedBy=network-online.target
WantedBy=multi-user.target
サービスファイルは作成後、以下のコマンドで以下の場所に保存します。
sudo cp oled_ip.service /etc/systemd/system/
networkd設定の有効化
serviceファイルに記載した「network-online.target」は、デフォルトで無効化されているため、以下の二つのコマンドで有効化を行います。
sudo systemctl enable systemd-networkd
sudo systemctl enable systemd-networkd-wait-online
サービスの再読み込み
サービスの作成と設定の有効化が終わったら、systemdに対してサービスの読み込みを行います。コマンドは以下の通りです。
sudo systemctl daemon reload
サービスの手動実行
読み込みが終わったら、以下のコマンドでサービスを手動起動させます。
sudo systemctl start oled_ip
startの後は、サービスファイルのファイル名(拡張子を除いた部分)を指定してください。
例) oled_id.service → oled_ip
実行状態の確認
サービス実行時のエラーの有無は、以下のステータスコマンドで確認できます。
sudo systemctl status oled_ip
以下のように表示されていれば、正常実行されて、ディスプレイにIPが表示されているはずです。
esu@raspberrypi:~ $ sudo systemctl status oled_ip
● oled_ip.service - Display IP on oled.
Loaded: loaded (/etc/systemd/system/oled_ip.service; enabled; preset: enabled)
Active: active (exited) since Sun 2024-07-07 22:21:31 BST; 47s ago
Process: 1953 ExecStart=/home/esu/src_python/oled_ip.sh (code=exited, status=0/SUCCESS)
Main PID: 1953 (code=exited, status=0/SUCCESS)
CPU: 123ms
Jul 07 22:21:31 raspberrypi systemd: Starting oled_ip.service - Display IP on oled....
Jul 07 22:21:31 raspberrypi systemd: Finished oled_ip.service - Display IP on oled..
自動実行の有効化
手動実行で動作が確認できたら、以下のコマンドで起動時の自動実行を有効化します。
sudo systemctl enable oled_ip
自動実行の確認
有効化が完了したら、RaspberryPiの電源をOFF・ONして自動実行を確認をします。
なお、今回のサービスの設定では、IPの取得のため「ネットワーク接続が確立されてからサービスを起動する」という設定になっています。
私の環境では電源ONから2分15秒ほどかかるので、しばらく待ってから確認するようにしてください。
しばらく待ってもIPが表示されない場合は、手動起動と同じく以下のコマンドで状態を確認してください。
sudo systemctl status oled_ip
今回使用した「ipget」は短いコードでIPが取得できますが、無線LANに未接続の状態で実行するとエラーになってしまい、ディスプレイ表示に失敗することが多々ありました。
コードをシンプルにするためこの記事では、networkdのサービス設定(ネットワークに接続してから実行)で回避していますが、より確実性を高めたい場合は
- ライブラリを変更して接続完了まで待つコードを入れる
- サービス設定内で失敗時のリトライを入れる
などで対策してみてください。
まとめ
raspberrypi5で、blinkaとCircuitPythonのライブラリを使って、OLEDディスプレイを使う方法を解説しました。
ライブラリのインストールや自動起動なので、記事自体は少々長くなってしまいましたが、Blinkaは、Picoなどのマイコン用のライブラリが、ノーマルのRaspberryPiでもそのまま使える、とても面白いカラクリです。
今回紹介したライブラリ以外にも、Blinkaが対応するライブラリはまだまだたくさんあるので、ぜひ皆さんも使ってみてください。
参考になればうれしいです。
おすすめの最新書籍
今月号の日経Interfaceは「Linuxチューニング術50」
今月号のInterfaceは『Linux チューニング術 50』です。
Linuxを組み込んだ機器を”本格的”に作ろうとすると「起動を早くしたい」「いきなり電源を切られてもデータを守りたい」など、対応が必要なチューニングはおおいですよね。
今回の記事は、「カーネルをいじらない」方法でチューニングを行う方法が解説されています。
こういった”実用的”な特集はレアですし、知っておいても損はない情報だと思います。
私も仕事でこの手の問題に何度も遭遇していますが、こういったOSレベルの難しそうな設定を、さらっとできちゃう人はかっこいいですよね。
興味のある方は、以下のリンクから確認できます。
質問・要望 大歓迎です
「こんな解説記事作って」「こんなことがしたいけど、〇〇で困ってる」など、コメント欄で教えてください。 質問・要望に、中の人ができる限り対応します。
使えたよ・設定できたよの一言コメントも大歓迎。気軽に足跡を残してみてください。記事を紹介したい方はブログ、SNSにバシバシ貼ってもらってOKです。