クリスマスの定番(?) Raspberry Pi と Philips Hue でクリスマスツリーをライティング (Nintendo Switch Joy-Con version)

この記事は、 ゆるWeb勉強会@札幌 Advent Calendar 2019 の25日目の記事です。

メリークリスマス!
アドベントカレンダーも最終日のクリスマス、そしてクリスマスと言えばラズパイですよね!

ということで、 ゆるWeb勉強会@札幌 Advent Calendar 2019 の最後はクリスマスツリーを照らすライトを制御する仕組みをRaspberry Piで作ってみたいと思います。

動画

Nintendo Switch の Joy-Con (L) で、ライトのON/OFF、明るさや色合いの調整を行なえるようにしています。

揃えるもの

Raspberry Pi

コントローラー

今回は、Nintendo Switch の Joy-Con (L) を使用します。

Hue

ライト

今回は、以前に “Echo Show” 購入時にセットで買ったものを(ようやく)活用。

ブリッジ

ブリッジを使って、 Raspberry Pi から Hue を繋ぎます。

より正確に言えばブリッジがWebサーバになっているので、 Raspberry Pi からブジッリに HTTP のリクエストを出すことで、 Hue の制御ができるようになります。

その他

  • ライトスタンド(LEDライトつけて大丈夫なもの)
  • ツリーなどの飾り

LEDライト共通の注意事項ですが、白熱電球とは 主に熱を持つ部分が異なります

白熱電球は発光部分のフィラメントを中心に熱を持ちますが、LEDライトはソケット部分を中心に熱を持ちます。
そのため、ソケット周辺がきちんと放熱される構造のスタンドをご使用ください。

Hue の設定

最初はスマホアプリを使って、ブジッリにライトを登録しておきます。
この辺りは、アプリの使用方法に沿って作業してください。

以降は、ブリッジと Raspberry Pi 、作業用のPCが全て同一のネットワークに存在する前提で進みます。

ブリッジのIPアドレス確認

ブリッジへHTTPリクエストを出すことになるので、IPアドレスを知っておく必要があります。
これは、ブリッジが正しく設定できていれば下記アドレスへアクセスすることで取得できます。

discovery.meethue.comjson; charset=utf-8 ファイル
 discovery.meethue.com
discovery.meethue.com
[
  {
    id: "XXXXXXXXXXXXXXXX",
    internalipaddress: "10.xxx.xxx.xxx"
  }
]

この internalipaddress が、現在接続されているネットワークでのIPアドレスになります。
メモっておきましょう。

ブリッジへユーザー登録

Raspberry Pi から操作する場合、ブリッジ上に一意のユーザーIDが必要になります。
ブリッジ本体にあるボタン(物理)を押した後に、下記のような形でHTTPリクエストを投げると、レスポンスの中に username が入っています。
こちらを、今後のHTTPリクエストで使うのでこちらもメモしておいてください。

ちなみに、 devicetype は各自で自由に設定可能です。

POST http://`internalipaddress`/api

body: {"devicetype":"tacck_hue_app#raspi"}
[
  {
    "success": {
      "username": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
    }
  }
]

ライトのID取得

続いて、ライトの操作をするためにブリッジに登録されているライトのIDを取得します。

GET http://`internalipaddress`/api/`username`/lights
{
  "1":{"state":{"on":false,"bri":254,...}
}

たくさん情報が返ってきますが、最初の "1" がIDになります。

下記のHTTPリクエストを投げると、ライトが点灯するはずです。
(trueのところをfalseにすれば、消灯します。)

internalipaddressusernamelight_idは、各自のものに置き換えてください。

PUT http://`internalipaddress`/api/`username`/lights/`light_id`/state

body: {"on":true}

Raspberry Pi

続いて、Raspberry Pi側のセッティングです。
Raspberry Piについては、すでにRaspbianが起動できている状態で、WiFiが利用可能な前提とします。

コントローラー

Joy-Con と Raspberry Pi は Bluetooth で接続します。

コマンドでも接続できるようですが、私が確認した感じだと、いまいちうまくできませんでした。(やりづらかった)

GUIを使って設定する方が楽だと思うので、そちらでやってみてください。

実装

では、コントローラーを使って Hue のライトを操作するように実装してみましょう。

実装には PyGame というライブラリを使用します。
これは、ゲーム関係のものを汎用的に取り扱えるライブラリで、 Joy-Con もいわゆるジョイスティックとして扱うことができるようになります。

また、私は普段Pythonを書かないので、インデントの谷に注意しながら実装していきます。

色々と調整して、下記のようなコードで落ち着きました。

joy-con.py

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import requests
import time
import pygame
import os

STEPS = 5

HUE_BRI_MIN = 0
HUE_BRI_MAX = 254
HUE_BRI_HALF = round((HUE_BRI_MAX - HUE_BRI_MIN + 1) / 2)
HUE_BRI_STEP = round(HUE_BRI_HALF / STEPS)
HUE_CT_MIN = 153
HUE_CT_MAX = 454
HUE_CT_HALF = round((HUE_CT_MAX - HUE_CT_MIN + 1) / 2)
HUE_CT_STEP = round(HUE_CT_HALF / STEPS)

HUE_API = 'http://`internalipaddress`/api/`username`/lights'

os.environ['SDL_FBDEV'] = '/dev/fb0'

if __name__ == '__main__':
    pygame.init()

    joys = pygame.joystick.Joystick(0)
    joys.init()

    # 照明の点灯状態
    light_on = False
    prev_light_on = light_on

    # 輝度・色調の初期値
    light_bri = HUE_BRI_MIN + HUE_BRI_HALF
    light_ct = HUE_CT_MIN + HUE_CT_HALF

    # パッドを押し続けた場合の管理用変数
    light_bri_loop_value = 0
    light_ct_loop_value = 0

    while True:
        events = pygame.event.get()
        for event in events:
            if event.type == pygame.JOYBUTTONDOWN or event.type == pygame.JOYHATMOTION:
                # print(event)

                if 'hat' in event.__dict__:
                    # print(event.value)
                    light_ct_loop_value = event.value[0]
                    light_bri_loop_value = event.value[1]
                
                # 13番ボタン(Joy-Con (L)のスクリーンショットボタン)で照明のON/OFFを制御
                if 'button' in event.__dict__ and event.button == 13:
                    # print(event.button)
                    light_on = not light_on

        # 横に押された場合色調を変更
        if light_ct_loop_value != 0:
            light_ct += light_ct_loop_value * HUE_CT_STEP
        if light_ct < HUE_CT_MIN:
            light_ct = HUE_CT_MIN
        if light_ct > HUE_CT_MAX:
            light_ct = HUE_CT_MAX

        # 縦に押された場合輝度を変更
        if light_bri_loop_value != 0:
            light_bri += light_bri_loop_value * HUE_BRI_STEP
        if light_bri < HUE_BRI_MIN:
            light_bri = HUE_BRI_MIN
        if light_bri > HUE_BRI_MAX:
            light_bri = HUE_BRI_MAX

        # Hue へ投げる
        if prev_light_on != light_on or light_on:
            requests.put(HUE_API + '/`light_id`/state', json = {"on": light_on, "bri": round(light_bri), "ct": round(light_ct)})

        # ON/OFF 確認用ログ
        if prev_light_on != light_on:
            print ('lignht_on:', light_on)

        prev_light_on = light_on
        time.sleep(0.1)

実行した結果が、冒頭の動画となります。
これを踏まえて、ぜひもう一度ご覧ください。

注意

今回は0.1秒ごとに投げていますが、ネットワークやブリッジの負荷は自己責任でお願いします。

まとめ

よくみると、先に挙げたアナザースタイルとよく似てる、、、と気づいた方もいらっしゃるかもしれません。

その通りです。

HueブリッジへHTTPリクエストを投げられる仕組みを作れば、かなり自由にシステムを作れることがわかっていただけたと思います。

Raspberry Pi で実装できるものなら、多くのことをトリガーとしてライトの制御ができることになります。
是非みなさんも、お手軽なスマートハウスとしてチャレンジしてみてください。

最後に

今年初めて企画したアドベントカレンダー、25日間欠けることなく埋めることができました。

投稿いただいたみなさま、SNSへの投稿やシェアをしていただいたみなさま、記事を見ていただいたみなさま、本当にありがとうございました。
当初はどのくらい埋まるかまったく読めなかったのですが、気づくと一気に埋めていただいていて、とても嬉しい誤算でした。
また、ゆるWeb勉強会未参加の方にも投稿いただけたのも、すごくありがたいです。ぜひ、勉強会の方にも遊びに来ていただけたらと思います。

Merry Christmas and Happy New Year!

tacck
  • tacck
  • 北の大地の普通のソフトウェアエンジニア。
    インフラ・バックエンド・フロントエンドと、色々やります。

    初心者・若手向けのメンターも希望あればお受けします。

    勉強会運営中
    * ゆるWeb勉強会@札幌
    * スマートスピーカーで遊ぼう会@札幌

コメントする

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください