RaspberryPiでデスク時計を作ろう

# RaspberryPiで作るスマート時計アプリケーション - RaspiWatch開発記

## はじめに

今回は、RaspberryPiを使用してデスクトップ時計アプリケーション「[RaspiWatch](https://github.com/jdpask21/RaspiWatch)」を開発しましたので、その実装方法について共有させていただきます。このアプリケーションは、時刻表示だけでなく、温度、湿度、天気情報なども表示できる多機能な時計アプリケーションとなっています。  
ちなみに、私の机の上でこんな感じで動いてくれています。  
![raspiwatch](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1684949/4087bf41-ce59-fea9-f536-b4d3b6ee6428.jpeg)

## 開発の背景

デスクに置ける多機能な時計が欲しいと思い、RaspberryPiとPythonを使って開発することにしました。単なる時計としての機能だけでなく、室内の環境モニタリングや天気予報機能も備えることで、より実用的なデバイスを目指しました。

## 機能紹介

RaspiWatchには以下のような機能があります：

1. リアルタイムの時刻表示
2. 大阪の天気情報表示（6時間ごとに更新）
3. 室内の温度・湿度モニタリング（DHT22センサーを使用）
4. フルスクリーン表示対応

## 必要な機材

- Raspberry Pi（任意のモデル）
- DHT22温度・湿度センサー
私はAmazonで買いました。→[Amazon](https://www.amazon.co.jp/gp/product/B0CLXHZHQM/ref=ppx_yo_dt_b_search_asin_title?ie=UTF8&psc=1)
- LCDディスプレイ
これもAmazonで買いました。私は3.5インチにしましたがなんでもいいと思います。→[Amazon](https://www.amazon.co.jp/gp/product/B01N5HW3BP/ref=ppx_yo_dt_b_search_asin_title?ie=UTF8&th=1)
- ~~10kΩ抵抗~~
- ジャンパーワイヤー
- Python 3.7以上の実行環境

## ハードウェアのセットアップ

### DHT22センサーの接続

DHT22センサーは以下のように接続します：

1. データピン → GPIO18（D18）
2. VCC → 3.3Vまたは5V電源
3. GND → グランド
4. ~~データピンとVCC間に10kΩ抵抗を接続~~  
（追記：抵抗は必要ありません）

## ソフトウェアの実装

### 使用している主要なライブラリ

- Flet: モダンなGUIアプリケーションを作成するためのPythonフレームワーク
- adafruit_dht: DHT22センサーを制御するためのライブラリ
- board: RaspberryPiのGPIOピンを制御するためのライブラリ

### アプリケーションの構造

アプリケーションは以下のような構造になっています：

```
RaspiWatch/
├── README.md
├── README_JP.md
├── requirements.txt
├── main.py
└── src/
    ├── get_now_time.py
    ├── get_weather.py
    └── get_temperature_humidity.py
```

### メインコードの解説

#### 1. 初期設定とレイアウト

```python
def main(page: ft.Page):
    # DHT22センサーの初期化
    dhtDevice = acd.DHT22(board.D18, use_pulseio=False)
    
    # ページの基本設定
    page.title = "Custom fonts"
    page.fonts = {
        "NnumGothic": "fonts/NanumGothic-ExtraBold.ttf",
    }
    page.theme = ft.Theme(font_family="NnumGothic")
    page.bgcolor = ft.colors.BLACK
    page.window.full_screen = True
```

アプリケーションの基本設定として、フォントの設定、背景色の設定、フルスクリーン表示の設定を行っています。

#### 2. 天気アイコンの管理

```python
def get_weather_icon():
    wb_code = get_weather.get_osaka_weather()
    if wb_code == 1:
        return wb_sunny
    elif wb_code == 2:
        return wb_cloudy
    # ... 他の天気パターン
```

天気情報を数値コードで取得し、対応するアイコンを返す関数を実装しています。この関数により、視覚的にわかりやすい天気表示を実現しています。

#### 3. メインループの実装

```python
while True:
    try:
        # 温度・湿度の取得と表示更新
        now_temp, now_humidity = get_temperature_humidity.get_temp_hum(dhtDevice)
        display_temp.value = now_temp
        display_humidity.value = now_humidity
    except RuntimeError as error:
        pass
    
    # 時刻の更新
    display_time.value, display_month.value, display_weekday.value, dt = get_str_time()
    
    # 天気情報の更新（6時間ごと）
    if (dt - old_time).seconds >= SIX_HOUR:
        try:
            weather.content = get_weather_icon()
        except Exception:
            weather.content = wb_unknown
        old_time = dt
    
    page.update()
    time.sleep(2.0)
```

メインループでは以下の処理を行っています：

1. 温度・湿度の定期的な取得と表示更新
2. 時刻表示の更新
3. 6時間ごとの天気情報更新
4. UIの更新

### レイアウトデザイン

アプリケーションのレイアウトは、Fletのコンテナとスタックを使用して実装しています：

```python
page.add(
    ft.Column(
        controls = [
            ft.Stack([
                # 天気アイコンと時刻表示のスタック
                ft.Row(controls=[weather]),
                ft.Container(
                    content=display_time,
                    alignment=ft.Alignment(0, -1),
                    bgcolor=ft.colors.TRANSPARENT,
                    width=2000,
                    height=700,
                ),
            ]),
            # 温度、湿度、日付、曜日の表示行
            ft.Row(controls=[...])
        ],
        alignment=ft.MainAxisAlignment.START,
        spacing=0,
    )
)
```

このレイアウト構造により、以下のような表示を実現しています：

- 大きな時刻表示（中央上部）
- 天気アイコン（左上）
- 温度・湿度表示（下部左側）
- 日付・曜日表示（下部右側）

## インストール方法

1. リポジトリのクローン：
```bash
git clone https://github.com/yourusername/RaspiWatch.git
```

2. 必要なパッケージのインストール：
```bash
pip install -r requirements.txt
```

3. アプリケーションの起動：
```bash
cd RaspiWatch
flet run watch_app
```

## 実装時の工夫点

1. **エラーハンドリング**
   - DHT22センサーの読み取りエラーに対する適切な例外処理
   - 天気情報の取得失敗時のフォールバック処理

2. **パフォーマンス最適化**
   - 天気情報の更新頻度を6時間に制限
   - センサーの読み取り間隔を2秒に設定

3. **ユーザビリティ**
   - フルスクリーン表示対応
   - 見やすい大きさのフォントとアイコン
   - 直感的なレイアウト設計

## 課題と今後の展望

1. **機能の拡張**
   - 複数都市の天気情報表示
   - アラーム機能の追加
   - カスタマイズ可能なテーマ設定

2. **改善点**
   - 設定のGUI化
   - エラー通知の改善
   - ネットワーク接続エラーへの対応強化

## まとめ

RaspiWatchは、RaspberryPiとPythonを使用して、実用的なデスクトップ時計アプリケーションを作成する方法を示しています。Fletフレームワークを使用することで、モダンなUIを持つアプリケーションを比較的簡単に作成することができました。

また、DHT22センサーを組み合わせることで、単なる時計以上の機能を持つIoTデバイスとして活用することができます。

## ライセンス

このプロジェクトはApache License 2.0の下で公開されています。詳細については、プロジェクトのLICENSEファイルをご確認ください。

## 参考文献

- [RaspiWatchリポジトリリンク](https://github.com/jdpask21/RaspiWatch)
- [Flet公式ドキュメント](https://flet.dev/)
- [Adafruit DHT22ライブラリドキュメント](https://github.com/adafruit/Adafruit_CircuitPython_DHT)
- [RaspberryPi公式ドキュメント](https://www.raspberrypi.com/documentation/)