新しいものづくりがわかるメディア

RSS


「土日で完成! 趣味のラズパイ」

土日で完成! 趣味のラズパイ ラズパイとChatGPTで遊ぼう——液晶時計を作る

本連載の第5回で「ラズパイを使ってデジタル時計を作る」というものを紹介しました。しかしこの記事で扱ったOLEDは0.96インチと小さいので、視認性に優れないのが欠点でした。

筆者がサイトをぐるぐる回っていたとき、Amazon.co.jpでそれより大きい2.42インチのOLEDを見つけました。SSD1309のコントローラーを利用しており、どうやらI2Cで使えそうです。これを使ってChatGPT 4でのプログラミングに挑戦しようかと購入しました。

抵抗の接続場所を変更してその他の端子を短絡させる

ただしこのOLEDはかなりのくせ者で、普通につないだだけでは何も認識せず、途方に暮れました。そこでいろいろと調べていると、I2Cで使うためには、R8につながれている0Ωの抵抗をR9側に移し、その上でR10、R11、R12を短絡させる必要があることが分かりました。裏面にはそう書いてあったのですが気付きませんでした……。この作業を終えて再度接続すると、0x3cのアドレスで接続できました。

この作業は初心者だと難しいかもしれませんが、挑戦してみるのは価値があります。特にR8に接続されている抵抗が外れにくく困りました。接続されている所にはんだを盛って溶かすことで外しました。

このようにR8の抵抗をR9に接続させ、リボンケーブルを外してからR10とR11、R12を短絡させる このようにR8の抵抗をR9に接続させ、リボンケーブルを外してからR10とR11、R12を短絡させる

接続されているのかはi2cdetectコマンドで分かるので、以下のように表示されるか確かめてみましょう。

$ i2cdetect -y 1
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:                         -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- 3c -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --

このように0x3cで認識されていればOKです。

いよいよChatGPTの登場

さてここまでできたところで、ChatGPTの登場です。質問を投げてみましょう。

なお、重要な大前提なのですが、以下の作業を最新のRaspberry Pi OSである「Bookworm」で実行したところ、Pythonライブラリがうまくインストールできませんでした。そのため、「Legacy」としてインストールできる、前のバージョンの「Bullseye」をインストールして構成しています。

まずメインメニューで「Raspberry Pi OS(Other)」を選び、「Raspberry Pi OS(Legacy,64-bit)」を選んでください。

「Raspberry Pi OS(Other)」を選ぶ 「Raspberry Pi OS(Other)」を選ぶ
「Raspberry Pi OS(Legacy,64-bit)」を選ぶ 「Raspberry Pi OS(Legacy,64-bit)」を選ぶ

ではChatGPTにプロンプトを入力します。


問い:Hopod 2.42 インチ OLED モジュールを利用してRaspberry Piでデジタル時計を作成したいです。その時のPythonプログラムを教えてください。Hopod 2.42 インチ OLED モジュールはSSD1309を利用しており、I2Cで接続するものとします。



このプロンプトに対する答えは以下のようなものでした。


Raspberry PiでHopod 2.42インチ OLED モジュール (SSD1309を利用、I2C接続) を使ってデジタル時計を作るには、まず必要なライブラリをインストールし、その後適切なPythonプログラムを書く必要があります。以下に、基本的な手順を示します。

### 前提条件
- Raspberry Piがセットアップされており、インターネットに接続できる状態であること。
- Raspberry PiにI2Cが有効になっていること。(`raspi-config` を使用して有効化できます)

### 必要なライブラリのインストール
1. **GPIOライブラリ**と**SMBusライブラリ**をインストールします(I2C通信に必要)。

    sudo apt-get update
    sudo apt-get install python3-smbus
    sudo apt-get install python3-rpi.gpio

2. **Pillow**(PILフォーク、画像処理ライブラリ)をインストールします。

    pip3 install Pillow

3. **SSD1306ライブラリ**をインストールします。このライブラリをSSD1309ディスプレイで使用することが多いです。

    pip3 install adafruit-circuitpython-ssd1309

### Pythonプログラム
以下はRaspberry PiでHopod 2.42インチ OLED モジュールを利用してデジタル時計を表示するための基本的なPythonスクリプトです。このスクリプトは、現在時刻を取得し、OLEDディスプレイに時刻を表示します。

import time
import board
import busio
from adafruit_ssd1306 import SSD1306_I2C
from PIL import Image, ImageDraw, ImageFont

# I2C接続設定
i2c = busio.I2C(board.SCL, board.SDA)
oled = SSD1306_I2C(128, 64, i2c)  # OLEDディスプレイの解像度とI2C接続を設定

# 画像と描画オブジェクトを作成
image = Image.new("1", (oled.width, oled.height))
draw = ImageDraw.Draw(image)

# フォントの設定 (デフォルトフォントを使用。必要に応じて変更してください)
font = ImageFont.load_default()

while True:
    # 現在の時刻を取得
    current_time = time.strftime("%H:%M:%S")

    # 画面をクリア
    draw.rectangle((0, 0, oled.width, oled.height), outline=0, fill=0)

    # 時刻を画面中央に描画
    text_width, text_height = draw.textsize(current_time, font=font)
    x = (oled.width - text_width) // 2
    y = (oled.height - text_height) // 2
    draw.text((x, y), current_time, font=font, fill=255)

    # 画像をOLEDディスプレイに表示
    oled.image(image)
    oled.show()

    # 1秒間隔で更新
    time.sleep(1)

### 注意点
- SSD1306ライブラリを使用していますが、多くの場合SSD1309ディスプレイと互換性があります。ただし、全ての機能が完全に互換性があるとは限らないため、特定の機能が期待通りに動作しない場合は、ライブラリのドキュメントを確認するか、コミュニティフォーラムでサポートを求めてください。
- このコードは基本的なデジタル時計の機能を提供しますが、カスタマイズや追加機能を実装することも可能です。たとえば、日付の表示やアラーム機能の追加などが考えられます。



このプロンプトではGPIOライブラリとSMBusライブラリ、Pillowをインストールするように言われますが、既に最新版のものがインストールされているので、作業する必要はありません。AdafruitのSSD1309ライブラリだけをインストールすればOKです。

インストールしたらPythonプログラムを「clock.py」などのファイル名で保存し、実行してみましょう。画像のように表示されれば動いています。

$ python clock2.py

時計を表示させてみたところ。縦に線が入っているのは実際に見えているわけではなく撮影上の問題なので故障ではない 時計を表示させてみたところ。縦に線が入っているのは実際に見えているわけではなく撮影上の問題なので故障ではない

曜日を表示させる

あっけなく動いてしまったので、かなり拍子抜けしました。こうなってくると欲が出てきます。曜日も入れましょう。文字も少し小さいので、大きくしてみます。再び、ChatGPTにプロンプトを入力します。


問い:文字のサイズを大きくして、曜日を入れてください



このプロンプトに対する答えは以下の通りでした。


文字のサイズを大きくして、曜日を追加するには、フォントのサイズを調整し、曜日を表示するコードを追加する必要があります。以下のスクリプトは、フォントサイズを大きくし、現在の時刻とともに曜日を表示するように更新されています。デフォルトフォントでは大きなサイズに対応していないため、`PIL`で使用可能なビルトインフォントの中から適切なものを選んで使用します。

import time
import board
import busio
from adafruit_ssd1306 import SSD1306_I2C
from PIL import Image, ImageDraw, ImageFont

# I2C接続設定
i2c = busio.I2C(board.SCL, board.SDA)
oled = SSD1306_I2C(128, 64, i2c)  # OLEDディスプレイの解像度とI2C接続を設定

# 画像と描画オブジェクトを作成
image = Image.new("1", (oled.width, oled.height))
draw = ImageDraw.Draw(image)

# カスタムフォントサイズの設定
# ビルトインフォントを使用しますが、より大きなサイズやカスタムフォントを使用する場合は、
# 適切な.ttfファイルを指定してください。
font_size = 20
font = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf", font_size)

# 曜日の表示に使用するフォントサイズ
day_font_size = 14
day_font = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf", day_font_size)

while True:
    # 現在の時刻と曜日を取得
    current_time = time.strftime("%H:%M:%S")
    current_day = time.strftime("%A")  # 曜日を取得

    # 画面をクリア
    draw.rectangle((0, 0, oled.width, oled.height), outline=0, fill=0)

    # 時刻を画面上部に描画
    time_width, time_height = draw.textsize(current_time, font=font)
    time_x = (oled.width - time_width) // 2
    time_y = 10
    draw.text((time_x, time_y), current_time, font=font, fill=255)

    # 曜日を時刻の下に描画
    day_width, day_height = draw.textsize(current_day, font=day_font)
    day_x = (oled.width - day_width) // 2
    day_y = time_y + time_height + 5  # 時刻の下に少し間隔を開ける
    draw.text((day_x, day_y), current_day, font=day_font, fill=255)

    # 画像をOLEDディスプレイに表示
    oled.image(image)
    oled.show()

    # 1秒間隔で更新
    time.sleep(1)

### 注意点
- 上記のコードではDejaVuSans-Boldフォントを使用しています。このフォントは多くのLinuxシステムにデフォルトでインストールされていますが、使用しているシステムによっては異なるフォントを指定する必要があるかもしれません。また、フォントファイルのパスもシステムによって異なる場合がありますので、適宜調整してください。
- フォントサイズ、テキストの位置、間隔などは、お使いのOLEDディスプレイの解像度や好みに応じて調整が必要です。



プログラムを修正して提示してくれました。こちらも「clock2.py」などのファイル名で保存したら実行してみましょう。

$ python clock2.py

少し文字が大きくなり、曜日も入って表示された 少し文字が大きくなり、曜日も入って表示された

曜日を日本語表記にする

プログラムは難なく改造できました。ただ、このままだと曜日が日本語表記になっていません。どうせなら日本語にしてみましょう。ChatGPTに入力するプロンプトは簡単です。


問い:曜日を日本語表記にしてください



これに対する答えは以下の通りです。


Pythonで曜日を日本語表記にするには、`locale` モジュールを使用してロケールを日本語に設定し、日付のフォーマットに `%A` を使用して曜日を取得します。ただし、Raspberry Pi OSや多くのLinuxディストリビューションでは、デフォルトで日本語ロケールがインストールされていない場合があります。そのため、最初に日本語ロケールをインストールする必要があるかもしれません。

### 日本語ロケールの設定(必要な場合)
1. Raspberry Piのターミナルを開きます。
2. `sudo dpkg-reconfigure locales` コマンドを実行し、表示されるリストから日本語ロケール(例: `ja_JP.UTF-8`)を選択して、ロケールを生成します。
3. 生成が完了したら、Raspberry Piを再起動するか、新しいシェルセッションを開始して変更を適用します。

### Pythonプログラムの更新
プログラム内で `locale` モジュールを設定し、`strftime` 関数を使用して曜日を日本語で取得します。以下は、曜日を日本語表記に更新したプログラムの一部です。

import locale
import time

# 日本語ロケールを設定
locale.setlocale(locale.LC_TIME, 'ja_JP.UTF-8')

# 無限ループ内で現在時刻と曜日を取得
while True:
    current_time = time.strftime("%H:%M:%S")
    current_day = time.strftime("%A")  # '%A'はロケールに基づいた完全な曜日名を返します

    # 以降のコードは時刻と曜日をディスプレイに表示する処理
    # 省略...

このコードスニペットでは、`locale.setlocale(locale.LC_TIME, 'ja_JP.UTF-8')` により、プログラムの日時関連の表示を日本語に設定しています。その後、`time.strftime("%A")` を使用して日本語の曜日名を取得し、OLEDディスプレイに表示することができます。

### 注意点
- この方法でロケールを設定すると、プログラム内の日時関連の表示が全て日本語になります。
- Raspberry Piに日本語ロケールがまだインストールされていない場合、上記の手順でロケールを追加する必要があります。これは一度だけ行えば十分です。
- `locale.setlocale` はプログラムのグローバルな状態を変更します。もし複数のロケールを使用するプログラムを書く場合は、影響範囲に注意してください。



どうでしょうか。おっと、日本語に対応するフォントではなかったようです。

フォントが対応していないので文字化けした フォントが対応していないので文字化けした

日本語対応についてもChatGPTに任せましょう。


問い:日本語表記できるフォントにしてください



この答えは以下の通りでした。


Raspberry PiでOLEDディスプレイに日本語の曜日を表示するためには、日本語をサポートするフォントが必要です。多くのLinuxシステムには、日本語フォントとして「Noto Sans CJK JP」が利用可能です。このフォントはGoogleが提供するNotoフォントファミリーの一部で、幅広い言語の文字をカバーしています。

### 日本語フォント「Noto Sans CJK JP」のインストール
もしまだインストールされていない場合は、以下のコマンドでインストールできます。

sudo apt-get update
sudo apt-get install fonts-noto-cjk

### Pythonプログラムの更新
日本語フォントを使用して曜日を表示するために、プログラムでフォントのパスを指定し、`ImageFont.truetype`関数でこのフォントを読み込むようにします。以下は、日本語フォントを使用して曜日を表示するプログラムの一部です。

from PIL import Image, ImageDraw, ImageFont

# 日本語フォントのパスを指定
# Noto Sans CJK JPフォントを使用
font_path = "/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc"

# フォントサイズを設定
font_size = 20

# ImageFontオブジェクトを作成
font = ImageFont.truetype(font_path, font_size)

# 曜日表示用の小さいフォントサイズ
day_font_size = 14
day_font = ImageFont.truetype(font_path, day_font_size)

# 以降のコードは、時刻と曜日をOLEDディスプレイに表示する処理
# 省略...

このコードスニペットでは、`/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc`をフォントのパスとして使用しています。このパスはNoto Sans CJK JPフォントがインストールされている一般的な場所ですが、システムによっては異なる場所にインストールされている場合があります。フォントの正確なパスを確認するには、ファイルシステムを検索するか、ターミナルで `fc-list` コマンドを使用して検索できます。

### 注意点
- 使用するフォントのパスは、インストールされているフォントとシステムの設定によって異なる場合があります。必要に応じてパスを調整してください。
- プログラムに組み込む前に、フォントが正しくインストールされていることを確認してください。フォントが見つからない場合、`ImageFont.truetype`はエラーを返します。



これらを総合して組んだプログラムは以下になります。こちらを最終的に実行すれば、日本語表記で曜日が出るはずです。「clock4.py」などの名前で保存してください。

import time
import board
import busio
import locale
from adafruit_ssd1306 import SSD1306_I2C
from PIL import Image, ImageDraw, ImageFont

# I2C接続設定
i2c = busio.I2C(board.SCL, board.SDA)
oled = SSD1306_I2C(128, 64, i2c)  # OLEDディスプレイの解像度とI2C接続を設定

# 画像と描画オブジェクトを作成
image = Image.new("1", (oled.width, oled.height))
draw = ImageDraw.Draw(image)

# 日本語ロケールを設定
locale.setlocale(locale.LC_TIME, 'ja_JP.UTF-8')

# 日本語フォントのパスを指定
# Noto Sans CJK JPフォントを使用
font_path = "/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc"

# フォントサイズを設定
font_size = 20

# ImageFontオブジェクトを作成
font = ImageFont.truetype(font_path, font_size)

# 曜日表示用の小さいフォントサイズ
day_font_size = 14
day_font = ImageFont.truetype(font_path, day_font_size)

# カスタムフォントサイズの設定
# ビルトインフォントを使用しますが、より大きなサイズやカスタムフォントを使用する場合は、
# 適切な.ttfファイルを指定してください。
#font_size = 20
#font = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf", font_size)

# 曜日の表示に使用するフォントサイズ
#day_font_size = 14
#day_font = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf", day_font_size)

while True:
    # 現在の時刻と曜日を取得
    current_time = time.strftime("%H:%M:%S")
    current_day = time.strftime("%A")  # 曜日を取得

    # 画面をクリア
    draw.rectangle((0, 0, oled.width, oled.height), outline=0, fill=0)

    # 時刻を画面上部に描画
    time_width, time_height = draw.textsize(current_time, font=font)
    time_x = (oled.width - time_width) // 2
    time_y = 10
    draw.text((time_x, time_y), current_time, font=font, fill=255)

    # 曜日を時刻の下に描画
    day_width, day_height = draw.textsize(current_day, font=day_font)
    day_x = (oled.width - day_width) // 2
    day_y = time_y + time_height + 5  # 時刻の下に少し間隔を開ける
    draw.text((day_x, day_y), current_day, font=day_font, fill=255)

    # 画像をOLEDディスプレイに表示
    oled.image(image)
    oled.show()

    # 1秒間隔で更新
    time.sleep(1)

では実行してみましょう。

$ python clock3.py

日本語表記で曜日が表示できるようになりました。

日本語表記で曜日が表示された 日本語表記で曜日が表示された

ここまで来るともっと欲が出て、「天気予報も表示できるようにならないか」と考えました。しかしこの手順はかなり複雑になってしまったので、回を改めてご紹介することにします。

ニュース

編集部のおすすめ

連載・シリーズ

注目のキーワード

もっと見る