土日で完成! 趣味のラズパイ ラズパイとChatGPTで遊ぼう——気温/湿度/気圧を測定する

前回まで、ChatGPTでラズパイに表示させるデジタル時計を作る作業について解説してきました。以前OLEDの「SO1602」とセンサー「BME280」を利用して温度と湿度、気圧を表示させる仕組みについて解説しましたが、SO1602は16文字×2行という制約があるため、あまり見栄えのよくないものでした。今回は時計にも使ったSSD1309を利用して、BME280で測定した気温と湿度、気圧を日本語で表示させる仕組みを作ってみましょう。

土日で完成! 趣味のラズパイ
第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回 ラズパイ工作の基本! 気温と湿度、気圧を計測する

では早速、ChatGPTに問いを投げかけてみます。


問い
Raspberry PiにBME280とSSD1309をI2C接続して、気温と気圧、湿度を測ってSSD1309に表示するPythonプログラムを教えてください


それに対する答えは以下のような内容でした。


Raspberry PiでBME280センサーとSSD1309 OLEDディスプレイをI2C接続して気温、気圧、湿度を測定し、SSD1309に表示するPythonプログラムの例を以下に示します。このプログラムには、AdafruitのBME280ライブラリとAdafruitのSSD1306ライブラリ(SSD1309はSSD1306の互換ディスプレイとして使用できます)を使用します。

### 必要なライブラリのインストール
まず、必要なPythonライブラリをインストールします。

```sh
pip install adafruit-circuitpython-bme280
pip install adafruit-circuitpython-ssd1306
pip install Pillow
```

### 配線
1. BME280:
– VCC -> 3.3V
– GND -> GND
– SCL -> SCL (GPIO 3)
– SDA -> SDA (GPIO 2)

2. SSD1309 (SSD1306互換):
– VCC -> 3.3V
– GND -> GND
– SCL -> SCL (GPIO 3)
– SDA -> SDA (GPIO 2)

### Pythonプログラム

```python
import time
import board
import busio
from adafruit_bme280 import basic as adafruit_bme280
from adafruit_ssd1306 import SSD1306_I2C
from PIL import Image, ImageDraw, ImageFont

# I2Cの設定
i2c = busio.I2C(board.SCL, board.SDA)

# BME280センサーの初期化
bme280 = adafruit_bme280.Adafruit_BME280_I2C(i2c)

# SSD1306 OLEDディスプレイの初期化(128x64ピクセル)
display = SSD1306_I2C(128, 64, i2c)

# ディスプレイバッファのクリア
display.fill(0)
display.show()

# フォントの読み込み(デフォルトフォント)
font = ImageFont.load_default()

while True:
    # 画像バッファの作成
    image = Image.new("1", (display.width, display.height))
    draw = ImageDraw.Draw(image)

    # BME280センサーからデータの読み取り
    temperature = bme280.temperature
    humidity = bme280.humidity
    pressure = bme280.pressure

    # データをディスプレイに描画
    draw.text((0, 0), f"Temp: {temperature:.1f} C", font=font, fill=255)
    draw.text((0, 16), f"Humidity: {humidity:.1f} %", font=font, fill=255)
    draw.text((0, 32), f"Pressure: {pressure:.1f} hPa", font=font, fill=255)

    # ディスプレイに描画したイメージを表示
    display.image(image)
    display.show()

    # 2秒ごとに更新
    time.sleep(2)
```

### 説明
1. **ライブラリのインストール**:
`adafruit-circuitpython-bme280`と`adafruit-circuitpython-ssd1306`ライブラリをインストールします。SSD1309はSSD1306の互換ディスプレイとして動作します。

2. **配線**:
BME280センサーとSSD1309ディスプレイをRaspberry PiにI2Cで接続します。

3. **プログラム**:
– `busio`を使用してI2C通信を設定します。
– `adafruit_bme280`と`adafruit_ssd1306`ライブラリを使用してセンサーとディスプレイを初期化します。
– `PIL`ライブラリを使用してテキストを描画し、ディスプレイに表示します。
– 2秒ごとにデータを更新してディスプレイに表示します。

このプログラムを実行することで、BME280センサーから取得した気温、湿度、気圧のデータをSSD1309 OLEDディスプレイに表示することができます。


ではこれに従って作業をしましょう。まずは前回同様、必要なPythonライブラリをインストールします。

$ pip install adafruit-circuitpython-bme280
$ pip install adafruit-circuitpython-ssd1306
$ pip install Pillow

配線については以下のようにします。I2C接続です。

●BME280:
VCC -> 3.3V
GND -> GND
SCL -> SCL(GPIO 3)
SDA -> SDA(GPIO 2)

●SSD1309(SSD1306互換):
VCC -> 3.3V
GND -> GND
SCL -> SCL(GPIO 3)
SDA -> SDA(GPIO 2)

I2C接続ではデイジーチェーンが可能なので、SCLとSDAは同じ場所に配線して問題ありません。

続いて、BME280とSSD1309が正しく接続されているか、コマンドで調べます。なおSSD1309は配線をし直す必要があるので、前回の解説を基に作業をしてください。

$ i2cdetect -y 1

このコマンドを入力した場合、以下のように0x3cと0x76に認識していれば問題ありません。

     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: -- -- -- -- -- -- 76 --

そして提示されたプログラムを「weather01.py」などのように保存して実行してみましょう。

$ python weather01.py

しかし以下のようなエラーを吐き出して実行できませんでした。

Traceback (most recent call last):
  File "/home/kimaf/.local/lib/python3.9/site-packages/adafruit_bus_device/i2c_device.py", line 175, in __probe_for_device
    self.i2c.writeto(self.device_address, b"")
  File "/home/kimaf/.local/lib/python3.9/site-packages/busio.py", line 220, in writeto
    return self._i2c.writeto(address, buffer, stop=True)
  File "/home/kimaf/.local/lib/python3.9/site-packages/adafruit_blinka/microcontroller/generic_linux/i2c.py", line 60, in writeto
    self._i2c_bus.write_bytes(address, buffer[start:end])
  File "/home/kimaf/.local/lib/python3.9/site-packages/Adafruit_PureIO/smbus.py", line 303, in write_bytes
    self._device.write(buf)
OSError: [Errno 121] Remote I/O error

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/kimaf/.local/lib/python3.9/site-packages/adafruit_bus_device/i2c_device.py", line 181, in __probe_for_device
    self.i2c.readfrom_into(self.device_address, result)
  File "/home/kimaf/.local/lib/python3.9/site-packages/busio.py", line 210, in readfrom_into
    return self._i2c.readfrom_into(address, buffer, stop=True)
  File "/home/kimaf/.local/lib/python3.9/site-packages/adafruit_blinka/microcontroller/generic_linux/i2c.py", line 67, in readfrom_into
    readin = self._i2c_bus.read_bytes(address, end - start)
  File "/home/kimaf/.local/lib/python3.9/site-packages/Adafruit_PureIO/smbus.py", line 170, in read_bytes
    return self._device.read(number)
OSError: [Errno 121] Remote I/O error

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/kimaf/weather01.py", line 12, in <module>
    bme280 = adafruit_bme280.Adafruit_BME280_I2C(i2c)
  File "/home/kimaf/.local/lib/python3.9/site-packages/adafruit_bme280/basic.py", line 368, in __init__
    super().__init__(I2C_Impl(i2c, address))
  File "/home/kimaf/.local/lib/python3.9/site-packages/adafruit_bme280/protocol.py", line 18, in __init__
    self._i2c = i2c_device.I2CDevice(i2c, address)
  File "/home/kimaf/.local/lib/python3.9/site-packages/adafruit_bus_device/i2c_device.py", line 62, in __init__
    self.__probe_for_device()
  File "/home/kimaf/.local/lib/python3.9/site-packages/adafruit_bus_device/i2c_device.py", line 184, in __probe_for_device
    raise ValueError("No I2C device at address: 0x%x" % self.device_address)
ValueError: No I2C device at address: 0x77

これもChatGPTに聞いてみることにしましょう。


問い
このプログラムを実行したところ、以下のようなエラーが出ました
(エラー略)


これに対するChatGPTの返答は以下のようなものでした。


このエラーメッセージは、指定したI2CアドレスにBME280センサーが見つからないことを示しています。いくつかの確認ポイントと解決方法を以下に示します。

### 確認ポイント

1. **配線の確認**:
– BME280センサーとRaspberry Piの間の配線が正しいことを確認してください。特にSCLとSDAが正しく接続されているか確認してください。

2. **I2Cの有効化**:
– I2CインターフェースがRaspberry Piで有効になっていることを確認してください。
`raspi-config`を使ってI2Cを有効化します。

1. **配線の確認**:
– BME280センサーとRaspberry Piの間の配線が正しいことを確認してください。特にSCLとSDAが正しく接続されているか確認してください。

     ```sh
     sudo raspi-config
     ```
     → `Interfacing Options` → `I2C` → `Enable`

3. **I2Cデバイスの検出**:
– 接続されたI2Cデバイスが正しく認識されているかを確認するために、`i2cdetect`コマンドを使用します。

     ```sh
     sudo apt-get install -y i2c-tools
     i2cdetect -y 1
     ```

– 正しく接続されている場合、BME280のデフォルトアドレス`0x77`または`0x76`が表示されます。

### プログラムの修正

もしBME280が`0x76`アドレスにある場合、プログラムを以下のように修正します。

```python
import time
import board
import busio
from adafruit_bme280 import basic as adafruit_bme280
from adafruit_ssd1306 import SSD1306_I2C
from PIL import Image, ImageDraw, ImageFont

# I2Cの設定
i2c = busio.I2C(board.SCL, board.SDA)

# BME280センサーの初期化 (アドレスを0x76に変更)
bme280 = adafruit_bme280.Adafruit_BME280_I2C(i2c, address=0x76)

# SSD1306 OLEDディスプレイの初期化(128x64ピクセル)
display = SSD1306_I2C(128, 64, i2c)

# ディスプレイバッファのクリア
display.fill(0)
display.show()

# フォントの読み込み(デフォルトフォント)
font = ImageFont.load_default()

while True:
    # 画像バッファの作成
    image = Image.new("1", (display.width, display.height))
    draw = ImageDraw.Draw(image)

    # BME280センサーからデータの読み取り
    temperature = bme280.temperature
    humidity = bme280.humidity
    pressure = bme280.pressure

    # データをディスプレイに描画
    draw.text((0, 0), f"Temp: {temperature:.1f} C", font=font, fill=255)
    draw.text((0, 16), f"Humidity: {humidity:.1f} %", font=font, fill=255)
    draw.text((0, 32), f"Pressure: {pressure:.1f} hPa", font=font, fill=255)

    # ディスプレイに描画したイメージを表示
    display.image(image)
    display.show()

    # 2秒ごとに更新
    time.sleep(2)
```

### 追加のデバッグ情報

– I2Cアドレスが正しいか確認するために、`i2cdetect`コマンドの出力を提供してください。
– それでも問題が解決しない場合は、配線やデバイス自体の故障の可能性も考慮してください。


先ほども確認したように、SSD1309は0x76と認識されています。どうやらI2Cのアドレス間違いが原因のようなので、提示されたプログラムを「weather02.py」と保存して実行してみましょう。

$ python weather02.py

すると以下のようにちゃんと気温と湿度、気圧が表示されました。

気温と湿度、気圧が表示された

では今回の本題に移ります。日本語で表示させる仕組みに変更します。


問い
このプログラムを日本語で表示させるように変更してください。日本語フォントのインストール方法も提示してください


それに対するChatGPTの返答は以下のようなものでした。


このプログラムを日本語で表示させるように変更し、日本語フォントのインストール方法も提示します。

### プログラムの日本語化
以下は、表示されるテキストを日本語に変更した例です。

```python
import time
import board
import busio
from adafruit_bme280 import basic as adafruit_bme280
from adafruit_ssd1306 import SSD1306_I2C
from PIL import Image, ImageDraw, ImageFont

# I2Cの設定
i2c = busio.I2C(board.SCL, board.SDA)

# BME280センサーの初期化 (アドレスを0x76に設定)
bme280 = adafruit_bme280.Adafruit_BME280_I2C(i2c, address=0x76)

# SSD1306 OLEDディスプレイの初期化(128x64ピクセル)
display = SSD1306_I2C(128, 64, i2c)

# ディスプレイバッファのクリア
display.fill(0)
display.show()

# 日本語フォントの読み込み
font_path = "/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc"
font = ImageFont.truetype(font_path, 14)

while True:
    # 画像バッファの作成
    image = Image.new("1", (display.width, display.height))
    draw = ImageDraw.Draw(image)

    # BME280センサーからデータの読み取り
    temperature = bme280.temperature
    humidity = bme280.humidity
    pressure = bme280.pressure

    # データをディスプレイに描画
    draw.text((0, 0), f"温度: {temperature:.1f} °C", font=font, fill=255)
    draw.text((0, 16), f"湿度: {humidity:.1f} %", font=font, fill=255)
    draw.text((0, 32), f"気圧: {pressure:.1f} hPa", font=font, fill=255)

    # ディスプレイに描画したイメージを表示
    display.image(image)
    display.show()

    # 2秒ごとに更新
    time.sleep(2)
```

### 日本語フォントのインストール方法
1. **必要なライブラリのインストール**:
– `PIL` (Pillow)
– 日本語フォント(例: DejaVuフォント)

   ```sh
   sudo apt-get update
   sudo apt-get install -y python3-pil fonts-dejavu
   ```

2. **プログラム内でフォントを指定**:

– 上記の例では、`/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf` を使用しています。他のフォントを使用したい場合は、そのパスを指定してください。

これでプログラムが日本語を表示するようになります。フォントのインストールが完了していれば、日本語の文字も正しく表示されるはずです。


ではその指示通りに進めていきましょう。まずは日本語フォントをインストールします。

$ sudo apt update && sudo apt upgrade -y
$ sudo apt install -y fonts-noto-cjk

なお、getの指示は必要ありませんので省略しました。またupdateの後にモジュールを最新のものにupgradeしています。

では最後に提示されたプログラムを「weather03.py」などのように保存して実行してみましょう。

$ python weather03.py

どうでしょうか。以下のように日本語で表示されていれば問題ありません。

日本語で気温と湿度、気圧が表示された

このようにSSD1309にBME280で測定したデータを日本語で表示させることができました。ChatGPTは簡単なプログラムを作成する際にはとても助けになります。他にも便利な手段があるか探っていきましょう。

fabcrossより転載)

関連情報

土日で完成! 趣味のラズパイ ラズパイとChatGPTで遊ぼう——気温/湿度/気圧を測定する (掲載元: fabcross)


ライタープロフィール
岩泉 茂

Raspberry Piと出会ってから7年。最初はArduinoに傾いていたが、Pythonにハマるうちにラズパイ一筋へ。そして小学校の時の電子工作熱が再び燃え上がり、GPIOを使って面白いものを作るのが楽しみとなる。あとこっそりとテツ。乗りテツ4割、模型テツ3割、撮りテツ2割、音テツ1割。今はラズパイで鉄道模型をコントロールすることに夢中。あとゆるいキャンプのアニメに触発されて、こちらもまた高校生以来のキャンプ熱再燃。コロナのおかげで行きづらくなったが、隔月くらいでキャンプしたいと思っている。

Twitter


関連記事

アーカイブ

fabcross
meitec
next
メルマガ登録
ページ上部へ戻る