📝 はじめに
Raspberry Pi に I2C 接続した SSD1306 OLED ディスプレイに、センサーデータやシステム情報を表示する方法を解説します。
対象読者
- Raspberry Pi で小型ディスプレイを活用したい人
- ヘッドレス環境でのデバッグ・監視方法を知りたい人
前提条件
- Raspberry Pi の I2C が有効化済み
- Python 3.10 以上
🎯 背景・動機
IoT センサーシステムを運用する中で、現場での確認が面倒(毎回 PC を開く必要がある)、ネットワーク接続前のデバッグが困難という課題がありました。小型の OLED ディスプレイを追加することで、ローカル表示機能を実装しました。
🛠️ 手順
1. ハードウェア接続
SSD1306 OLED ディスプレイを I2C バスに接続します。
| SSD1306 | Raspberry Pi |
|---|---|
| VCC | 3.3V (Pin 1) |
| GND | GND (Pin 6) |
| SDA | GPIO 2 / SDA (Pin 3) |
| SCL | GPIO 3 / SCL (Pin 5) |
ディスプレイ仕様: 128 x 64 ピクセル、モノクロ、I2C アドレス: 0x3C
i2cdetect -y 1 で 0x3c に認識されることを確認します。
2. 必要なライブラリ
[tool.poetry.dependencies]
adafruit-blinka = "^8.47.0"
adafruit-circuitpython-ssd1306 = "^2.12.15"
pillow = "^10.0.0"
3. OLED ディスプレイクラスの実装
import logging
logger = logging.getLogger(__name__)
class OLEDDisplay:
def __init__(self, address=0x3c, width=128, height=64):
self.address = address
self.width = width
self.height = height
self.display = None
self.is_available = False
def init_display(self):
try:
import board
import adafruit_ssd1306
i2c = board.I2C()
self.display = adafruit_ssd1306.SSD1306_I2C(
self.width, self.height, i2c, addr=self.address
)
self.display.fill(0)
self.display.show()
self.is_available = True
return True
except Exception as e:
logger.warning(f'OLED 初期化失敗: {e}')
return False
def clear(self):
if self.is_available and self.display:
self.display.fill(0)
self.display.show()
4. Pillow を使った画像描画
SSD1306 は Pillow の Image オブジェクトを直接表示できます。
def show_sensor_data(self, temperature, humidity):
if not self.is_available:
return
from PIL import Image, ImageDraw, ImageFont
# 128x64 の白黒画像を作成
image = Image.new("1", (self.width, self.height))
draw = ImageDraw.Draw(image)
try:
font_large = ImageFont.truetype(
"/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf", 20
)
font_label = ImageFont.truetype(
"/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", 12
)
except:
font_large = font_label = ImageFont.load_default()
# センサーデータを描画
draw.text((0, 10), "Temp:", font=font_label, fill=255)
draw.text((55, 10), f"{temperature:.1f}C", font=font_large, fill=255)
draw.text((0, 40), "Humid:", font=font_label, fill=255)
draw.text((55, 40), f"{humidity:.1f}%", font=font_large, fill=255)
# ディスプレイに表示
self.display.image(image)
self.display.show()
5. システム情報の表示
def show_system_info(self, hostname, ip_address=None):
if not self.is_available:
return
from PIL import Image, ImageDraw, ImageFont
image = Image.new("1", (self.width, self.height))
draw = ImageDraw.Draw(image)
try:
font = ImageFont.truetype(
"/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf", 18
)
except:
font = ImageFont.load_default()
draw.text((5, 15), hostname[:20], font=font, fill=255)
if ip_address:
draw.text((5, 43), ip_address, font=font, fill=255)
self.display.image(image)
self.display.show()
🚨 つまずきポイント
フォントが見つからない
Docker コンテナ内ではフォントがない場合があります。Dockerfile に追加するか、フォールバック処理を実装します。
RUN apt-get install -y fonts-dejavu-core
ディスプレイが点灯しない
- I2C アドレスを確認(0x3C または 0x3D の場合がある)
- 配線を確認(特に VCC/GND)
文字がはみ出る
128x64 ピクセルの制約内でレイアウトを設計します。hostname[:20] のように文字数制限を設けましょう。
📈 まとめ
- ヘッドレス環境でのデバッグが改善: IP アドレスやセンサー状態を即座に確認可能
- Pillow を使った柔軟な描画: テキスト、図形を自由に配置
-
フェイルセーフの重要性:
is_availableフラグでディスプレイ未接続でもシステム動作継続