「土日で完成! 趣味のラズパイ」
土日で完成! 趣味のラズパイ ラズパイとChatGPTで遊ぼう——液晶時計を作る
本連載の第5回で「ラズパイを使ってデジタル時計を作る」というものを紹介しました。しかしこの記事で扱ったOLEDは0.96インチと小さいので、視認性に優れないのが欠点でした。
筆者がサイトをぐるぐる回っていたとき、Amazon.co.jpでそれより大きい2.42インチのOLEDを見つけました。SSD1309のコントローラーを利用しており、どうやらI2Cで使えそうです。これを使ってChatGPT 4でのプログラミングに挑戦しようかと購入しました。
土日で完成! 趣味のラズパイ
第16回 ラズパイとChatGPTで遊ぼう——圧電ブザーで音を鳴らす
第15回 ラズパイとChatGPTで遊ぼう——気温/湿度/気圧を測定する
第14回 ChatGPTで遊ぼう——ラズパイで作ったデジタル時計に天気情報も表示させる
第13回 ラズパイとChatGPTで遊ぼう——液晶時計を作る
第12回 ラズパイとChatGPTで遊ぶ——その1:Lチカさせてみる
第11回 ラズパイをブリッジモードで使って、Wi-Fi接続する
第10回 ラズパイをWi-Fiルーターにする
特別編 【実機レビュー】よりパワフルになったRaspberry Pi 5を検証!
第9回 VolumioでラズパイからSpotifyやradikoを楽しむ
第8回 ラズパイで音楽プレーヤー「Volumio」を楽しむ
第7回 GPSを導入して正確な時刻を刻む
第6回 ラズパイをNTPサーバーにする
第5回 ラズパイを使ってデジタル時計を作る
第4回 Raspberry Pi Camera Module 3を使って見守りカメラを作る
第3回 BME680の測定データを小型ディスプレイに表示させる
第2回 空気質センサー「BME680」で空気汚染度を測る
第1回 ラズパイ工作の基本! 気温と湿度、気圧を計測する
一覧ページへ
抵抗の接続場所を変更してその他の端子を短絡させる
ただしこのOLEDはかなりのくせ者で、普通につないだだけでは何も認識せず、途方に暮れました。そこでいろいろと調べていると、I2Cで使うためには、R8につながれている0Ωの抵抗をR9側に移し、その上でR10、R11、R12を短絡させる必要があることが分かりました。裏面にはそう書いてあったのですが気付きませんでした……。この作業を終えて再度接続すると、0x3cのアドレスで接続できました。
この作業は初心者だと難しいかもしれませんが、挑戦してみるのは価値があります。特にR8に接続されている抵抗が外れにくく困りました。接続されている所にはんだを盛って溶かすことで外しました。
接続されているのかは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)」を選んでください。
では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
日本語表記で曜日が表示できるようになりました。
ここまで来るともっと欲が出て、「天気予報も表示できるようにならないか」と考えました。しかしこの手順はかなり複雑になってしまったので、回を改めてご紹介することにします。